
/*******************************************************************************************
applicationTest.qs
Copyright (C) 2009 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/
function applicationTest() {
	print(Application.version);
	print(Application.version.major);
	print(Application.version.minor);
	print(Application.version.build);
	print(Application.version.revision);
	print(Application.version.full);
	print(Application.name);
	print(Application.name + " " + Application.version);
}
/*******************************************************************************************
applyLayoutTemplateAndPrint.qs
Copyright (C) 2009 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

/* 
This function finds first spectrum in the document, by its type and subtype chooses 
a layout template document to apply, applies it and prints the result.

To set up the function it is necessary to do the following: 
1. Define a directory where layout templates will be placed. Set this directory to layoutTemplatesDir variable.
2. Create layout template files which cover all your cases. 
Their names are spectral type and subtype: 1D1H.mnova, 1D13C.mnova, 2D1H13C.mnlt, etc. 
*/
function applyLayoutTemplateAndPrint(aToPDF) {
	if (Application.version.revision < 4657) {
		MessageBox.critical("Your version of MNova doesn't support all the functionality of the script. Upgrade to the latest version of MNova.");
		return;
	}

	// The below settings must be changed
	layoutTemplatesDir = Dir.application();

	// Find first NMR item in the document. By this item we will chose layout template document.
	var specItem;
	dw = new DocumentWindow(mainWindow.activeWindow());
	for (i = 0; i < dw.pageCount(); i++) {
		p = new Page(dw.page(i));
		if (p.itemCount("NMR Spectrum")) {
			specItem = p.item(0, "NMR Spectrum");
			break;
		}
	}
	if (specItem == undefined) {
		return;
	}

	// Check that appropriate layout template document exists. Expected names are 1D1H.mnova, 1D13C.mnova, 2D1H13C.mnlt, etc. 
	// See more details below.
	layoutTemplateDocumentName = layoutTemplatesDir + "/" + specItem.type + specItem.subtype + ".mnova";
	if (!File.exists(layoutTemplateDocumentName)) {
		return;
	}

	// Save current document copy to the temporary directory
	tempDocName = Dir.temp() + "/applyLayoutTemplateAndPrint.mnova";
	oldFileHistory = serialization.fileHistory;
	serialization.fileHistory = false;
	serialization.save(tempDocName);

	// Open previously saved document
	serialization.open(tempDocName);
	serialization.fileHistory = oldFileHistory;

	// Apply layout template
	tempDw = new DocumentWindow(mainWindow.activeWindow());
	oldTemplateHistory = tempDw.templateHistory;
	tempDw.templateHistory = false;
	tempDw.applyTemplateDocument(layoutTemplateDocumentName);
	tempDw.templateHistory = oldTemplateHistory;

	// Print the result document
	if (aToPDF)
		mainWindow.doAction("action_File_ExportToPDF");
	else
		mainWindow.doAction("action_File_Print");
	// Close temporary document
	mainWindow.activeWindow().close();
	// Delete temporary file
	File.remove(tempDocName);
	// Activate old active window 
	mainWindow.setActiveWindow(dw);
}

/******************************************************************************************************
assignmentTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/*jslint plusplus: true, nomen: true, indent: 4, white: true*/
/*global Molecule, molecule, nmr, MoleculePlugin, Application, Atom, NMRAssignments*/

function assignmentTest() {
	"use strict";
	var atomNumber = 6,
		h = 1,
		moleculePlugin = new MoleculePlugin(Application.molecule),
		mol, atom, assign, shift;

	if (moleculePlugin === undefined) {
		return;
	}

	mol = new Molecule(moleculePlugin.activeMolecule());
	if (mol.isValid() === false) {
		throw "Invalid Molecule";
	}

	atom = new Atom(mol.atom(atomNumber));
	print(atom.text);
	assign = new NMRAssignments(mol);
	print(assign);
	shift = assign.chemShift(atomNumber, h);
	if (shift !== undefined) {
		print(JSON.stringify(shift, null, 2));
	}

	//assign to single value
	assign.setChemShift(6, 0, 13.5);
	//assign to range
	assign.setChemShift(6, 1, 1.0, 2.0);
	//assing to range with value
	assign.setChemShift(3, 1, 1.25, 2, 1.30);
	//assing with two objects
	assign.setChemShift({ "index": 11, "h": "a" },
		{ "shift": 1.9, "min": 1.85, "max": 1.92 });
	//assing with one object
	assign.setChemShift({
		"atom": { "index": 21, "h": "b" },
		"shift": [2.6, 2.65] //this assigns to a list of values
	});
}

function assignedMoleculeTest() {
	'use strict';
	var mol = new Molecule(Application.molecule.activeMolecule()),
		assignments;

	if (!mol.isValid()) {
		throw "Invalid Molecule";
	}

	assignments = mol.nmrAssignments();
	print(JSON.stringify(assignments, null, 2));
}

function setAssignmentsTest() {
	'use strict';

	var mol = new Molecule(Application.molecule.activeMolecule()),
		assignments;

	if (!mol.isValid()) {
		throw "Invalid Molecule";
	}

	assignments = [
		{ atom: { index: 3 }, shift: [13, 14] },
		{ atom: { index: 4, h: 'a' }, shift: [{ min: 7.21, max: 7.25 }] },
		{ atom: { index: 6, h: 'a' }, shift: [7.95] },
		{
			atom: { index: 7, h: 'a' }, shift: [{ min: 1.20, max: 1.25, shift: 1.21 },
			{ min: 2, max: 2.5, shift: 2.45 }]
		}
	];
	mol.setNMRAssignments(assignments, true); //the second parameter clears all previous assignments

	var assigns = new NMRAssignments(mol);
	assigns.setChemShift(10, 1, 7.215, 7.255);
	assigns.setChemShift(11, 2, 5, 5.5, 5.12);
}

function jsTest() {
	'use strict';

	var mol = new Molecule(Application.molecule.activeMolecule()),
		assignments = mol.nmrAssignments(),
		nmrAssignsObj = new NMRAssignments(mol);

	if (!mol.isValid()) {
		throw "Invalid Molecule";
	}

	print(JSON.stringify(assignments, null, 2));

	print(JSON.stringify(nmrAssignsObj.jConsts(4, 1)));
	print(JSON.stringify(nmrAssignsObj.ambigJs(9, 1)));

	nmrAssignsObj.setJConsts(11, 1, [{ "atom": { "h": "a", "index": 13 }, "value": 5 }]);
	print(JSON.stringify(mol.nmrAssignments(), null, 2));
}

function filteredNMRAssignments() {
	"use strict";

	var mol = molecule.activeMolecule(),
		molAssignments = mol.nmrAssignments(), //this returns an array with all assignments
		nmrSpc = nmr.activeSpectrum(),
		peaks = nmrSpc.peaks(),
		multiplets = nmrSpc.multiplets(),
		integrals = nmrSpc.integrals(),
		peakAssignments, assignPeaks;

	print("Peaks size {0}".format(peaks.count));
	print("Integrals size {0}".format(integrals.count));
	print("Multiplets size {0}".format(multiplets.count));

	//returns a filtered hard-copy
	function getByShiftFilter(aAssignments, aFilterFunc) {
		var assignments;

		assignments = aAssignments.map(function (aAtomAssignment) {
			//deep copy
			var newVal = JSON.parse(JSON.stringify(aAtomAssignment));
			newVal.shift = newVal.shift.filter(aFilterFunc);
			return newVal;
		});

		return assignments.filter(function (aAtomAssignment) {
			return aAtomAssignment.shift.length;
		});
	}

	//returns an array with the assignments of a specific type
	function getByShiftType(aAssignments, aType) {
		return getByShiftFilter(aAssignments, function (aShiftValue) {
			return aShiftValue.type === aType;
		});
	}

	//returns an array with the assignments to an specific UUID (peak, multiplet, integral)
	function getByShiftUUID(aAssignments, aUUID) {
		return getByShiftFilter(aAssignments, function (aShiftValue) {
			return aShiftValue.uuid === aUUID;
		});
	}

	//returns a filtered hard-copy
	function getByAtomFilter(aAssignments, aFilterFunc) {
		var assignments;
		assignments = aAssignments.filter(aFilterFunc);

		//return a deep copy of the object
		return assignments.map(function (aAtomAssignment) {
			return JSON.parse(JSON.stringify(aAtomAssignment));
		});
	}

	//returns an array with the assignments to an specific element
	function getByElement(aAssignments, aElem) {
		return getByAtomFilter(aAssignments, function (aAtomAssignment) {
			return aAtomAssignment.element === aElem;
		});
	}

	//returns an array with the assignements to an specific atom number
	function getByAtomIndex(aAssignments, aAtomIndex) {
		return getByAtomFilter(aAssignments, function (aAtomAssignment) {
			return aAtomAssignment.atom.index === aAtomIndex;
		});
	}

	//Filter the list of assignments by type. getByShiftType returns a deep copy!
	print("By Peak:");
	peakAssignments = getByShiftType(molAssignments, "Peak");
	print(JSON.stringify(peakAssignments, null, 2));
	print("By Multiplet:");
	print(JSON.stringify(getByShiftType(molAssignments, "Multiplet"), null, 2));
	print("By Integral:");
	print(JSON.stringify(getByShiftType(molAssignments, "Integral"), null, 2));

	//Filter the list of assignments by UUID
	print("By UUID {20c222a1-d47c-442d-a60c-716fe825df61}"); //it's a UUID the type does not matter
	print(JSON.stringify(
		getByShiftUUID(
			molAssignments,
			"{20c222a1-d47c-442d-a60c-716fe825df61}"), null, 2));

	//Filter the list of assignments by element symbol
	print("By Element H:");
	print(JSON.stringify(getByElement(molAssignments, "H"), null, 2));
	print("By Element C:");
	print(JSON.stringify(getByElement(molAssignments, "C"), null, 2));

	//Filter by atom number
	print("By Atom Index 14");
	print(JSON.stringify(getByAtomIndex(molAssignments, 14), null, 2));

	//get assigned peaks
	function shiftToPeakList(aAtomAssignment) {
		return aAtomAssignment.shift.reduce(
			function (aTotal, aCurrentVal) {
				aTotal.push(peaks.byId(aCurrentVal.uuid));
				return aTotal;
			}, []);
	}

	if (peakAssignments.length) {
		assignPeaks = shiftToPeakList(peakAssignments[0]);
		assignPeaks.forEach(function (aPeak) {
			print("Shift: {0}. Intensity: {1}".format(
				aPeak.delta(1), aPeak.intensity));
		});
	}
}

/*******************************************************************************************
attachmentsExample.qs
Copyright (C) 2015 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

function setAttachmentExample() {
	var txtMetaData = { "field1": 20, "field2": "Meta" };
	var txtAtt = new Attachment();
	txtAtt.setMetaData(txtMetaData);
	txtAtt.setTextData("This is my first Attachment");
	mainWindow.activeDocument.setAttachment("TextAttachment", txtAtt);

	var binAtt = new Attachment();
	if (binAtt.setBinaryDataFromFile("/tmp/tux_butterfly.png") !== 0) {
		print("Binary bytes saved: ", binAtt.size);
		binAtt.setMetaDataValue("FileName", "tux_butterfly.png");
		mainWindow.activeDocument.setAttachment("BinAttachment", binAtt);
	}
}

function getAttachmentExample() {
	var atts = mainWindow.activeDocument.attachmentNames();
	for (var i = 0; i < atts.length; ++i) {
		var att = mainWindow.activeDocument.getAttachment(atts[i]);
		print("Attachment: ", atts[i]);
		if (att) {
			print("\tAtt meta: ", JSON.stringify(att.getMetaData()));
			if (att.isText) {
				print("\tAtt text: ", att.textData());
			} else {
				var fileName = att.getMetaDataValue("FileName", "NoName");
				print("\tBinary bytes written: ", att.binaryDataAsFile("/tmp/%1".arg(fileName)));
			}
		}
	}
}
/*******************************************************************************************
binaryStreamTest.qs
Copyright (C) 2010 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

function binaryStreamTest() {
	var f = new File(Dir.temp() + "/MNova_TextStream_Test.bin");
	f.open(File.WriteOnly);
	print(f);

	var s = new BinaryStream(f);
	print(s);

	s.writeInt8(8);
	s.writeInt16(16);
	s.writeInt32(32);
	s.writeInt64(64);
	s.writeBool(true);
	s.writeReal32(3.14);
	s.writeReal64(3.1415);
	s.writeString("- Hellow BinaryStream!");
	s.writeCString("- Hellow, hellow...");
	s.writeBytes("- Hi, all!", 4);
	s.writeBytes([45, 32, 72, 105])
	print(s);

	f.close();
	f.open(File.ReadOnly);
	print(s.readInt8());
	print(s.readInt16());
	print(s.readInt32());
	print(s.readInt64());
	print(s.readBool());
	print(s.readReal32());
	print(s.readReal64());
	print(s.readString());
	print(s.readCString());
	var b = s.readBytes(4)
	print(String.fromCharCode(b[0], b[1], b[2], b[3]));
	var b = s.readBytes(4)
	print(String.fromCharCode(b[0], b[1], b[2], b[3]));

	f.close();
	f.remove();
}

/******************************************************************************************************
blindRegions.qs
Copyright (C) 2011 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/** Take blind region list from active spectrum, print some info and append a new blind region
*/
function blindRegionTest() {
	var nmrSpc = nmr.activeSpectrum()
	if (nmrSpc.isValid()) {
		//get blind regions array
		var blindRegionsArray = nmrSpc.blindRegions;
		print(blindRegionsArray);
		//remove the last one
		if (blindRegionsArray.lenght != 0)
			blindRegionsArray.pop();
		//create a new one
		var newBlindRegion = new BlindRegion(5.5, 6.0);
		newBlindRegion.name = "My Region"
		//print some info.
		print(newBlindRegion.f1.from)
		print(newBlindRegion.f1.to)
		print(newBlindRegion)
		//append to the array
		blindRegionsArray.push(newBlindRegion);
		print(blindRegionsArray);
		//json like
		var jsonString = '{"name": "Another", "f1": {"from":"2.1","to":"3"} }';
		var anotherBlindRegion = JSON.parse(jsonString)
		print(anotherBlindRegion.f1.from)
		print(JSON.stringify(anotherBlindRegion));
		//apply to spectrum
		nmrSpc.auditTrail.addCommand(function () {
			nmrSpc.blindRegions = blindRegionsArray;
			nmrSpc.update();
			mainWindow.activeWindow().update();
		}, null, null, "Set Blind Regions", { "data": JSON.stringify(blindRegionsArray) });
	}
}

/** Takes the blind region list from the active spectrum and saves it to a file that can be opended from the GUI
*/
function blindRegionExport() {
	var nmrSpc = nmr.activeSpectrum()
	if (nmrSpc.isValid()) {
		var blindRegionsArray = nmrSpc.blindRegions;
		if (blindRegionsArray.lenght != 0) {
			//array to xml string
			var xmlString = BlindRegion.exportList(blindRegionsArray);
			print(xmlString);
			//get file name
			var filename = FileDialog.getSaveFileName("*.xml;;*.*", "Save To File", Dir.home())
			var file = new File(filename);
			if (file.open(File.WriteOnly)) {
				//write to file
				var strm = new TextStream(file);
				strm.write(xmlString);
				strm.flush();
			}
		}
	}
}

/** Reads blind region list from file and applies it to the active spectrum
*/
function blindRegionImport() {
	var nmrSpc = nmr.activeSpectrum()
	if (nmrSpc.isValid()) {
		//get filename
		var filename = FileDialog.getOpenFileName("*.xml;;*.*", "Import File", Dir.home())
		var file = new File(filename);
		if (file.open(File.ReadOnly)) {
			//read the xml string
			var strm = new TextStream(file);
			var xmlString = strm.readAll(xmlString);
			//create the list
			var blindRegionsArray = BlindRegion.importList(xmlString);
			print(blindRegionsArray);
			//apply to spectrum
			nmrSpc.blindRegions = blindRegionsArray;
			nmrSpc.update();
			mainWindow.activeWindow().update();
		}
	}
}

/******************************************************************************************************
byteArrayTest.qs
Copyright (C) 2012 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function byteArrayReadTest() {
	"use strict";
	var bArr = new ByteArray("This\nis\na\nbyteArray"),
		txtStrm = new TextStream(bArr, File.ReadOnly);

	print(txtStrm.readLine());
	print(txtStrm.readLine());
}

function byteArrayWriteTest() {
	"use strict";
	var bArr = new ByteArray(),
		txtStrm = new TextStream(bArr, File.WriteOnly);

	txtStrm.writeln("This");
	txtStrm.writeln("is");
	txtStrm.writeln("a");
	txtStrm.writeln("ByteArray");

	print(bArr.toString());
}

/******************************************************************************************************
cloningObjects.qs
Copyright (C) 2010 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function cloningObjects() {
	var w = mainWindow.activeDocument
	var p = w.curPage()

	//Create some items
	var text = draw.text("<b>This is text</b>", true)
	text.translate(200, 200)
	text.color = "cyan"
	print(text)
	print(text.plainText)

	var rect = draw.rectangle(p.width / 3, p.height / 3);
	rect.translate(50, 75);
	rect.angle = 45;
	rect.color = "red";
	rect.opacity = 50;
	print(rect);

	var arrow = draw.arrow(p.right, p.top, p.left, p.bottom, false, true);
	arrow.startX = (p.right + p.left) / 2.0;
	arrow.startY = p.top + 100;
	arrow.lineColor = "blue";
	arrow.lineStyle = PageItem.DashLine;
	print(arrow);

	var ellipse = draw.ellipse(p.width / 2, p.height / 2);
	ellipse.angle = 90;
	ellipse.lineStyle = PageItem.DashDotLine;
	//ellipse.color = "pink";
	print(ellipse);

	//create a new page
	var newPage = w.newPage()

	//clone the text item in the new page
	var clonedItem = newPage.cloneItems(text);
	print("cloned Item " + clonedItem);

	//another page and clone the rectangle and the arrow there
	newPage = w.newPage()
	var itemArray = []
	itemArray[0] = rect;
	itemArray[1] = arrow;

	var clonedArray = newPage.cloneItems(itemArray);
	print("number of clones " + clonedArray.length);

	//clone the entire page
	var anotherPage = w.clonePages(newPage);
	print(anotherPage);

	//newPage.deleteItems(clonedArray);
	//print(clonedArray[0]);

	w.update();
}

function editingPages() {
	var w = mainWindow.activeDocument
	draw.text("Initial Page", true);

	w.addPage();
	draw.text("Added at end", true);

	w.addPage(1);
	draw.text("Inserted at 1", true);

	var pageToMove = new Page(w.addPage());
	draw.text("Page added to the end and moved to 1", true);
	w.movePages(1, pageToMove);

	var pageToMove2 = w.addPage();
	draw.text("Pages added to the end and moved to 2", true);
	var pageToMove3 = w.addPage();
	draw.text("Pages added to the end and moved to 2", true);
	w.movePages(2, [pageToMove2, pageToMove3]);

	w.update();
}

/*******************************************************************************************
createSpectrumTest.qs
Copyright (C) 2016 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

/*globals NMRPredictorParams, NMRSpectrum*/

function createSpectrumTest() {
	'use strict';
}

createSpectrumTest.spectrum1D = function () {
	'use strict';
	var predParams = new NMRPredictorParams("1H"),
		peaks = [{ frequency: 1.0 }];
	return new NMRSpectrum(predParams, peaks, true);
};

createSpectrumTest.spectrum2D = function () {
	'use strict';
	var predParamsF2 = new NMRPredictorParams("1H"),
		predParamsF1 = new NMRPredictorParams("13C"),
		peaksF2 = [{ frequency: 1.0 }],
		peaksF1 = [{ frequency: 20.0 }];
	predParamsF2.size = 1024;
	predParamsF1.size = 256;
	return new NMRSpectrum(predParamsF2, peaksF2, predParamsF1, peaksF1, true);
};

createSpectrumTest.multipletXML = function () {
	'use strict';
	var multXML = '<mnova-multiplets version="1.0"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Mnova-Multiplet.xsd"><!--ppm. Default H:-2, C:-20--><from>2</from><!--ppm. Default H:12, C:230--><to>10</to><!--MHz. Default H:500.13, C:125--><frequency>400</frequency><!--Default Chloroform-d--><solvent>Chloroform-d</solvent><!--Default based on the range of the shifts--><nucleus>H1</nucleus><!--Default 32*1024 --><!-- <nPoints>32768</nPoints> --><multipletList><multiplet><!--8.07 (dt, J = 8.0, 0.7, 0.7 Hz, 1H)--><!--Default 1 --><numberOfNuclides>1</numberOfNuclides><shift>8.07</shift><jList><j>8.0</j><j>0.7</j><j>0.7</j></jList></multiplet><multiplet><!--5.88 (dq, J = 6.6, 3.3, 3.3, 2.1 Hz, 1H)--><numberOfNuclides>1</numberOfNuclides><shift>5.88</shift><jList><j>6.6</j><j>3.3</j><j>3.3</j><j>2.1</j></jList></multiplet><multiplet><!--3.92 (dd, J = 4.0, 2.2 Hz, 1H)--><numberOfNuclides>1</numberOfNuclides><shift>3.92</shift><jList><j>4.0</j><j>2.2</j></jList></multiplet></multipletList></mnova-multiplets>';
	return new NMRSpectrum(multXML);
};

createSpectrumTest.peakXML = function () {
	'use strict';
	var peakXML = '<mnova-peaks version="1.0"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Mnova-Peak.xsd"><spectrum><dim><from>2</from><to>10</to><frequency>400</frequency><nucleus>H1</nucleus><nPoints>32768</nPoints></dim><solvent>Chloroform-d</solvent></spectrum><peakList><peak><heigth>2</heigth><dim><shift>3</shift><width>0.1</width></dim></peak><peak><heigth>3</heigth><dim><shift>4</shift><width>0.1</width></dim></peak></peakList></mnova-peaks>';
	return new NMRSpectrum(peakXML);
};

/******************************************************************************************************
customImportProcessing.qs
Copyright (C) 2012 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/** The Env.DefaultNMRProcessingSetup can be set to a function that will be called everytime a NMR spectrum is imported. If an exception is thrown or the value returned is an error or a boolean false then Mnova will use the default processing. No returned value is interpreted as no error.
 * The function will receive as "this" object the NMRProcessing object initialized by Mnova that will be applied to the spectrum and as a parameter an object containing the relevant information parsed at this moment from the file. 
 * Properties available in the spectrum info object:
 * - coord[]: an array in which the nth element will have this info about the nth dimension of the experiment: pts,zero,width,Hz,MHz,nucleus,Ph0,Ph1
 * - originalFormat: a string with the imported format
 * - other parameters avaliable: DataFileName, Title, Comment, Origin, Owner, Site, Spectrometer, Author, Solvent, Temperature, PulseSequence, Experiment, NumberofScans, ReceiverGain, RelaxationDelay, PulseWidth, AcquisitionTime, AcquisitionDate, ModificationDate, SpectrometerFrequency, SpectralWidth, LowestFrequency, Nucleus, AcquiredSize, SpectralSize.
 * For 1D, all of them are strings, for 2D experiments some of this parameters are arrays having the information about the nth dimension in the nth element. Use print(JSON.stringify(aSpcInfo)) to see all the properties
 * Check example functions below.
 */
Env.DefaultNMRProcessingSetup = noProcessing
//Env.DefaultNMRProcessingSetup = clearMnovaProcessing
//Env.DefaultNMRProcessingSetup = baselineCorrection
//Env.DefaultNMRProcessingSetup = processingFormat
//Env.DefaultNMRProcessingSetup = processingFromFile
//Env.DefaultNMRProcessingSetup = apodization

/**
 * This function will not process the spectrum. The original FID will be shown
 */
function noProcessing(aSpcInfo) {
	print(JSON.stringify(aSpcInfo))
	if (aSpcInfo.nDim == 1) {
		this.stopProc = NMRProcessing.OriginalFID
	}
}

/**
 * Mnova will always construct a default processing object based on the properties of the spectrum. If the user wants to have full control of the initial processing, before modifying the "this" object setApplyNothing must be called
*/
function clearMnovaProcessing(aSpcInfo) {
	//print(JSON.stringify(aSpcInfo))
	this.setApplyNothing()

	//add processing here...
}


/**
 * This function will apply a baseline correction using Bernstein algorithm only for 1D experiments
 */
function baselineCorrection(aSpcInfo) {
	//print(JSON.stringify(aSpcInfo))
	if (aSpcInfo.nDim == 1) {
		this.setParameter("BC[1].apply", true)
		this.setParameter("BC[1].algorithm", "Bernstein")
	}
}

/**
 * This function will load a processing template from a file
 */
function processingFromFile(aSpcInfo) {
	//print(JSON.stringify(aSpcInfo))
	if (this.open("/home/isaac/tmp/myProcTemplate.mnp") == false) //import proc
		MessageBox.critical("Failed to open processing template")//this will show the message but Mnova will open the file and use the default processing
}

/**
 * This function will apply apodization to the imported spectrum
 */
function apodization(aSpcInfo) {
	//print(JSON.stringify(aSpcInfo))
	this.setParameter("Apodization[1].Exp.apply", true)
	this.setParameter("Apodization[1].Exp.value", 0.5)
	this.setParameter("Apodization[1].fp.apply", true)
	this.setParameter("Apodization[1].fp.value", 0.5)
}

/**
 * This function will apply different processing templates based on the original format. Check NMRSpectrum.originalFormat for information about the possible values.
 */
function processingFormat(aSpcInfo) {
	//print(JSON.stringify(aSpcInfo))
	if (aSpcInfo.originalFormat == "Varian") {
		this.stopProc = NMRProcessing.ProcessedFID //no proc
	} else if (aSpcInfo.originalFormat == "JEOL Delta") {
		if (this.open("/home/isaac/tmp/myProcTemplate.mnp") == false) //import proc
			MessageBox.critical("Failed to open processing template!")
	} else if (aSpcInfo.originalFormat == "Bruker WIN-NMR") {
		if (aSpcInfo.nDim == 1) {//modify apodization
			this.setParameter("Apodization[1].Exp.apply", true)
			this.setParameter("Apodization[1].Exp.value", 0.5)
			this.setParameter("Apodization[1].fp.apply", true)
			this.setParameter("Apodization[1].fp.value", 0.5)
		}
	}
}

/******************************************************************************************************
customMultipletLabel.qs
Copyright (C) 2009 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
function customMultipletLabel() {
	MultipletLabelReporter.call(this);

	this.name = "My Multiplet Label";
}
customMultipletLabel.prototype = new MultipletLabelReporter();
customMultipletLabel.prototype.report = function (aMultiplet) {
	var multLabel = new String("%1\n%3");
	multLabel = multLabel.replace("%1", aMultiplet.name).replace("%2", aMultiplet.category).replace("%3", aMultiplet.delta.toFixed(2));
	return multLabel;
}

Env.MultipletLabelFunctions.push(new customMultipletLabel());


/******************************************************************************************************
customMultipletReporter.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

var MyMultipletReporterSettingsKey = new String("MyMultipletReporter/Custom Message");

/* This creates a Custom Multiplet Reporter  */
function MyMultipletReporter() {
	MultipletReporter.call(this);

	var setts = new Settings(Application.settings);
	this.customMessage = setts.value(MyMultipletReporterSettingsKey, "My Multiplet Reporter");

	this.name = "My Multiplet Reporter";

	this.onlyElementName = false;
	// Define font size and font family
	this.font = "<font style=\"font-size: 10pt; font-family: Times New Roman\">";

	this.nucleusTemplate = "%1";
	// Report header. %1 will be raplaced with nucleusString, %2  with frequency, %3 with solvent 
	this.header = this.customMessage + " %1 NMR (%2 MHz, %3) &delta; ";
	//this.header = "Custom %1 NMR (%2 MHz, %3) &delta; ";

	// Multiplet templates. %1 - delta, %2 - category, %3 - nH
	this.reportRange = true; // set to true to get multiplet range instead of delta.
	this.withoutJsTemplate = " %1 (%2, %3H)"; // multiplet template without J's
	this.withJsTemplate = " %1 (%2, %4, %3H)"; //  multiplet template with J's
	this.rangeTemplate = "%1 &ndash; %2";

	// J's list template. %1 - list of J's
	this.jListTemplate = "<i>J</i> = %1";

	this.jPrecision = 1; // J's precision
	this.deltaPrecision = 2; // delta precision
	this.mSeparator = ", "; // multiplet separator 
	this.jSeparator = ", "; // J's separator	
	this.sortJAscending = true;
	this.start = "<html><head><title>Multiplet Report</title></head><body>" + this.font;
	this.end = ".</font></body></html>";
}

MyMultipletReporter.prototype = new MultipletReporter();
MyMultipletReporter.prototype.toString = function () { return "MyMultipletReporter()"; }

//This line adds my custom reporter to the list of reporters, this means that this reporter can be used by the general functions like reportMultipletsUser or automaticMultipletReport and it can be used to generate reports  from the Multiplets Table
Env.MultipletReportersArray.push(new MyMultipletReporter());

//Uncomment this line to make this reporter the default reporter, the saved settings will be ignored, the user will not be able to modify the reporter from MNova
//Env.DefaultMultipletReporter = "My Multiplet Reporter";


//This function can be used to generate multiplet reports
function customReportMultipletsUser(createItem) {
	var multipletTable = new MultipletTable(nmr.multipletTable()); // Get table of multiplets
	var spectrum;
	if (multipletTable.isValid())
		spectrum = new NMRSpectrum(multipletTable.spectrum()); // Get spectrum currently shown in the table of multiplets
	else
		spectrum = new NMRSpectrum(nmr.activeSpectrum());

	if (spectrum.isValid()) {
		var reporter = MultipletReporter.getReporterByName("My Multiplet Reporter");
		return reporter.report(spectrum, createItem);
	}
	else
		return undefined;
}

//Uncomment this line to use the previous function to report multiplets instead of the default one
//Env.ReportMultipletsUser = customReportMultipletsUser;

//Function to setup my reporter
function customReportMultipletsUserSetup() {
	var rep = MultipletReporter.getReporterByName("My Multiplet Reporter");

	var diag = new Dialog();
	diag.title = "Custom Setup";

	var lEdit = new LineEdit();
	lEdit.text = rep.customMessage;
	diag.add(lEdit);

	if (diag.exec()) {
		rep.customMessage = lEdit.text;
		settings.setValue(MyMultipletReporterSettingsKey, rep.customMessage);
	}
}

//Uncomment this line to use the previous function to setup the report multiplets
//Env.ReportMultipletsUserSetup = customReportMultipletsUserSetup;

/******************************************************************************************************
customPeakReporter.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

var MyPeakReporterSettingsKey = new String("MyPeakReporter/Custom Message");

/* This creates a Custom Peak Reporter  */
function MyPeakReporter() {
	PeakReporter.call(this);

	var setts = new Settings(Application.settings);
	this.customMessage = setts.value(MyPeakReporterSettingsKey, "My Peak Reporter");

	this.name = "My Peak Reporter";

	// Define font size and font family
	this.font = "<font style=\"font-size: 10pt; font-family: Times New Roman\">";

	this.nucleusTemplate = "%1";
	// Report header. %1 will be raplaced with nucleusString, %2  with frequency, %3 with solvent 
	//this.header = "My Peak Reporter %1 NMR (%2 MHz, %3) &delta; ";
	this.header = this.customMessage + " %1 NMR (%2 MHz, %3) &delta; ";
	//Peak templates:
	this.peakTemplate = "%1";//%1 - delta

	this.deltaPrecision = 2; // delta precision
	this.pSeparator = ", "; // peak separator 

	this.start = "<html><head><title>Peak Report</title></head><body>" + this.font;
	this.end = ".</font></body></html>";
}

MyPeakReporter.prototype = new PeakReporter();
MyPeakReporter.prototype.toString = function () { return "MyPeakReporter()"; }

//This line adds my custom reporter to the list of reporters, this means that this reporter can be used by the functions like reportPeaksUser or automaticPeakReport and then it can be used to generate reports  from the Peaks Table
Env.PeakReportersArray.push(new MyPeakReporter());

//Uncomment this line to make this reporter the default reporter, the saved settings will be ignored, the user will not be able to modify the reporter from MNova
//Env.DefaultPeakReporter="My Peak Reporter";

//This function can be used to generate peak reports
function customReportPeaksUser(createItem) {
	var peakTable = new PeakTable(nmr.peakTable()); // Get table of peaks
	var spectrum;
	if (peakTable.isValid())
		spectrum = new NMRSpectrum(peakTable.spectrum()); // Get spectrum currently shown in the table of peaks
	else
		spectrum = new NMRSpectrum(nmr.activeSpectrum());

	if (spectrum.isValid()) {
		var reporter = PeakReporter.getReporterByName("My Peak Reporter");
		return reporter.report(spectrum, createItem);
	}
	else
		return undefined;
}

//Uncomment this line to use the previous function to report multiplets instead of the default one
//Env.ReportPeaksUser = customReportPeaksUser;

//Function to setup my reporter
function customReportPeaksUserSetup() {
	var rep = PeakReporter.getReporterByName("My Peak Reporter");

	var diag = new Dialog();
	diag.title = "Custom Setup";

	var lEdit = new LineEdit();
	lEdit.text = rep.customMessage;
	diag.add(lEdit);

	if (diag.exec()) {
		rep.customMessage = lEdit.text;
		settings.setValue(MyPeakReporterSettingsKey, rep.customMessage);
	}
}

//Uncomment this line to use the previous function to setup the report peaks
//Env.ReportPeaksUserSetup = customReportPeaksUserSetup;

/*******************************************************************************************
customScriptActions.qs
Copyright (C) 2016 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

/*globals Action, Application, MessageBox, mnDebug, mnError*/
/*jslint plusplus: true, indent: 4, white: true*/

Application.addScriptAction("NMRMultipletsTable", {
	"reportMenu": [
		{
			type: "QAction",
			text: "My Multiplet Report",
			objectName: "customMultipletReport",
			icon: ":/images/table.png",
			toolTip: "This is an example",
			//checkable: true,
			//checked: false,
			onTriggered: function () {
				'use strict';
				MessageBox.information("Triggered %1 from %2".arg(this.text).arg(this.widget.objectName));
			},
			//onToggled: function (aToggled) {
			//MessageBox.information("Toggled ", aToggled);
			//}
		}
	],
});

Application.addScriptAction("NMRPeaksTable", {
	"nmrPeaksTableToolbar": [
		{
			type: "QAction",
			objectName: "separator",
			isSeparator: true
		},
		{
			type: "QAction",
			text: "My Peak Action",
			objectName: "customPeakAction",
			icon: ":/images/table.png",
			toolTip: "This is an example",
			//checkable: true,
			//checked: false,
			onTriggered: function () {
				'use strict';
				MessageBox.information("Triggered %1 from %2".arg(this.text).arg(this.widget.objectName));
			},
			onCreated: function () {
				'use strict';
				mnDebug("%1 created".arg(this.objectName));
				if (this.widget) {
					this.widget.dataUpdated.connect(this, this.onDataUpdated);
				} else {
					mnError("No widget");
				}
			},
			onDataUpdated: function () {
				'use strict';
				mnDebug("%1 data updated".arg(this.widget.objectName));
			}
		}
	]
});

/******************************************************************************************************
dbAddNamedFields.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

// This function adds two named text fields to the current page in the current document.
// It is intended as an example on how to add custom fields to a layout document for later storage in MnDB.
// The field contents can be retrieved by setting the field content definition accordingly when creating the
// database, e.g.: '=getNamedTextField("Field", "[ProjectName]")'.
// The function getNamedTextField(aType, aSubtype) is defined in DBPlugin.qs.

function addNamedFields() {
	var w = new DocumentWindow(mainWindow.activeWindow());
	var p = new Page(w.curPage());

	var label1 = draw.text("Project Name:", false);
	label1.translate(0, 40);
	label1.width = 50;

	var field1 = draw.text("( Fill in project name )", "Field", "[ProjectName]", false);
	field1.translate(50, 40);
	field1.width = 90;
	field1.color = "lightgray";
	field1.opacity = 30;

	var label2 = draw.text("Analysis Comments:", false);
	label2.translate(0, 60);
	label2.width = 50;

	var field2 = draw.text("( Fill in analysis comments )", "Field", "[Comments]", false);
	field2.translate(50, 60);
	field2.width = 90;
	field2.height = 100;
	field2.color = "lightgray";
	field2.opacity = 30;

	w.update();
}

/******************************************************************************************************
dbBrowserExample.qs
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals Application, DBPlugin, qsTr, MessageBox, ProgressDialog, print*/
/*jslint plusplus: true, indent: 4*/

function dbBrowserExample() {
	"use strict";
	var hits, hit, h, i, recordIds, records, r, rid, record, items, item, fieldNames, f,
		db = DBPlugin.client,
		progress = new ProgressDialog();

	// Choose database
	Application.mainWindow.doAction("dbDatabaseOpen");
	if (!(db.connected() && db.database.length > 0)) {
		return;
	}

	// Do a search 
	print("Searching for '-' ...");
	hits = DBPlugin.search(db, "-", "TEXT", "Molecule");
	MessageBox.information(qsTr("{0} hits found.").format(hits.length));

	// Collect record ids 
	recordIds = [];
	for (h = 0; h < hits.length; h++) {
		hit = hits.at(h);
		print(" Hit " + h + ": Record=" + hit.recordId() + " Item=" + hit.itemId() + " Score=" + hit.score() + " (" + hit.toString() + ")");
		if (recordIds.indexOf(hit.recordId()) < 0) {
			recordIds.push(hit.recordId());
		}
	}

	// Retrieve records
	records = [];
	progress.setRange(0, recordIds.length);
	progress.show();
	for (r = 0; r < recordIds.length && !progress.wasCanceled; r++) {
		rid = recordIds[r];
		progress.value = r;
		progress.labelText = qsTr("Retrieving record {0} ({1} of {2})...").format(rid, r + 1, recordIds.length);
		Application.mainWindow.processEvents();
		print("Retrieving record " + rid + "...");
		record = DBPlugin.getRecord(DBPlugin.client, rid, false);
		//print(record);
		items = record.items();
		print("Retrieved " + items.length + " items from record " + record.url() + ".");
		for (i = 0; i < items.length; i++) {
			item = items[i];
			//print(item);
			//print(JSON.stringify(item.fieldNames()));
			fieldNames = item.fieldNames();
			for (f = 0; f < fieldNames.length; f++) {
				print("     " + f + ":" + fieldNames[f] + ":" + item.field(fieldNames[f]));
			}
		}
		records.push(record);
	}
	progress.close();
	DBPlugin.createBrowser(records);
}

/******************************************************************************************************
dbMandatoryFieldsExample1.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

// This is an example for saving custom, mandatory fields to MnDB. 
// To use: 
// 1. Create a new database with two added custom fields "Project" and "NotebookRef" in the Molecule item type.
// 2. Place this script in one of the Mnova scripts folders.
// 3. Start saving to the new db. A dialog asking for the content of the mandatory fields will show with each save operation.        
// 4. Customize the function dbPreSaveHook according to your needs.

// This function, when in the global namespace, is called when saving to database, after selecting the items 
// to be saved but before sending the data to the server.
// Parameters: aDBClient - DBClient object which is connected to the server we want to save to
//                   aDB - DBDefinition object for the database where items will be saved to
//             aRecordId - ID of the record to be updated, or 0 for a new record (Currently always 0)
//              aDBItems - Items to be saved under this record
function dbPreSaveHook(aDBClient, aDB, aRecordId, aDBItems, aShowErrors, aInteractive) {
	if (!(aDB.hasField("Molecule", "Project") && aDB.hasField("Molecule", "NotebookRef")))
		return;

	// Construct a dialog for Project Number and Notebook Reference Number
	var dialog = new Dialog();
	dialog.title = "Data Fields";

	var gbMain = new GroupBox();
	gbMain.title = "Mandatory Fields";
	dialog.add(gbMain);

	var leProject = new LineEdit();
	leProject.label = "Project";
	gbMain.add(leProject);

	var leNotebookRef = new LineEdit();
	leNotebookRef.label = "Notebook Ref.";
	gbMain.add(leNotebookRef);

	// Pop up the dialog until either all fields are filled in or cancel is pressed
	var done = false;
	while (!done && aDBItems.length > 0) {
		var result = dialog.exec();
		if (result == 0) {
			MessageBox.information("Save cancelled.");
			aDBItems.length = 0;
		}
		else if (!leProject.text.length > 0)
			MessageBox.information("You need to fill in the project number.");
		else if (!leNotebookRef.text.length > 0)
			MessageBox.information("You need to fill in the Notebook reference.");
		else
			done = true;
	}

	// Set item fields to the entered values
	for (var i = 0; i < aDBItems.length; i++) {
		if (aDBItems[i].type == "Molecule") {
			aDBItems[i].setField("Project", leProject.text);
			aDBItems[i].setField("NotebookRef", leNotebookRef.text);
		}
	}
}


/******************************************************************************************************
dbMandatoryFieldsExample2.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

// This is an example for checking that mandatory fields have been filled in when saving to MnDB. 
// It can be used with layout templates containg named fields (see dbAddNamedFields.qs)
// To use: 
// 1. Place this script in one of the Mnova scripts folders.
// 2. Start saving to the new db. 
// 4. Customize the function dbPreSaveHook according to your needs.

// This function, when in the global namespace, is called when saving to database, after selecting the items 
// to be saved but before sending the data to the server.
// Parameters: aDBClient - DBClient object which is connected to the server we want to save to
//                   aDB - DBDefinition object for the database where items will be saved to
//             aRecordId - ID of the record to be updated, or 0 for a new record (Currently always 0)
//              aDBItems - Items to be saved under this record
function dbPreSaveHook(aDBClient, aDB, aRecordId, aDBItems, aShowErrors, aInteractive) {
	if (!(aDB.hasField("Molecule", "Project")))
		return;

	var projectName = getNamedTextField("Field", "[ProjectName]")
	if (projectName == null || projectName == "-") {
		MessageBox.information("Error: Project information is not set. Aborting Save.");
		aDBItems.length = 0;
	}
	else if (projectName.length != 10) {
		MessageBox.information("Error: Project information must be exactly 10 characters. Aborting Save.");
		aDBItems.length = 0;
	}
}


/******************************************************************************************************
dbPasteHooksExample.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals
	print, MessageBox */
/*jslint plusplus: true, indent: 4 */


// Example dbPrePasteHook() and dbPostPasteHook() functions.
// To use, place this script in one of the Mnova scripts folders.

// This function, when in the global namespace, is called for each db item before pasting from MnDB to Mnova. 
// It must return true for the paste operation to proceed.

function dbPrePasteHook(aItemUrl, aDB, aItem) {
	"use strict";
	var msg = "Trying to paste {0} from database {1} ({2}).".format(aItem.type, aDB.name, aItemUrl);
	// msg += "\naDB=" + aDB.toString() + "\naItem=" + aItem.toString();
	print(msg);
	MessageBox.information(msg, MessageBox.Ok);
	// Paste only molecules
	if (aItem.type === "Molecule") {
		return true;
	}
	return false;
}

// This function, when in the global namespace, is called once after each successful pasting operation from MnDB to Mnova.
function dbPostPasteHook(aUuids) {
	"use strict";
	var i, msg = "dbPostPasteHook: Pasted {0} items.".format(aUuids.length);
	for (i = 0; i < aUuids.length; i++) {
		msg += "\nItem {0}: {1}".format(i, aUuids[i]);
	}
	MessageBox.information(msg, MessageBox.Ok);
}

// The end.

/******************************************************************************************************
dbPeakSearch.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals
		nmr, mainWindow, getTotalRegionPPM, getVisibleRegionPPM, isBetween, print, DBPlugin, MessageBox, Multiplets, NMRSpectrum, Peak, Peaks, Settings */
/*jslint plusplus: true, indent: 4*/


function getPeakQueryInterval(aPrefix, aValue, aTolerance, aInclude) {
	"use strict";
	return aInclude ? (aPrefix + " " + (aValue - aTolerance).toPrecision(6) + " " + (aValue + aTolerance).toPrecision(6)) : "";
}

// Returns a peak search query clause for a single NMR Peak
function getPeakQueryClause(aPeak, aSpec) {
	"use strict";
	var
		settingsKey = "DBSearch/Settings/Peak Search/" + (aSpec.dimCount === 2 ? "2D" : "1D"),
		settings = new Settings(settingsKey),
		posTolerance1 = aSpec.nucleus(1, false) === "1H" ? settings.value("Position/1H", 0.1) : settings.value("Position/Other", 1.0),
		posTolerance2 = aSpec.nucleus(2, false) === "1H" ? settings.value("Position/1H", 0.1) : settings.value("Position/Other", 1.0),
		widthTolerance = settings.value("Width", 1.0),
		intensityTolerance = settings.value("Intensity", 1.0),
		restrictPeakType = settings.value("TypeMustMatch", false),
		restrictPeakFlags = settings.value("FlagsMustMatch", false),
		restrictMultiplicity = false,

		includePosX = true,
		includePosY = aSpec.dimCount === 2,
		includeWidthX = widthTolerance < 1.0 && !isNaN(aPeak.width(1)) && aPeak.width(1) > 0.0,
		includeWidthY = widthTolerance < 1.0 && aSpec.dimCount === 2 && !isNaN(aPeak.width(2)) && aPeak.width(2) > 0.0,
		includeIntensity = intensityTolerance < 1.0 && !isNaN(aPeak.intensity) && aPeak.intensity !== 0.0,

		result = getPeakQueryInterval("Px:", aPeak.delta(1), posTolerance1, includePosX)
			+ getPeakQueryInterval(" Py:", aPeak.delta(2), posTolerance2, includePosY)
			+ getPeakQueryInterval(" Wx:", aPeak.width(1), aPeak.width(1) * widthTolerance, includeWidthX)
			+ getPeakQueryInterval(" Wy:", aPeak.width(2), aPeak.width(2) * widthTolerance, includeWidthY)
			+ getPeakQueryInterval(" I:", aPeak.intensity, aPeak.intensity * intensityTolerance, includeIntensity);

	if (restrictPeakType) {
		result += " T: " + aPeak.typeToString();
	}
	if (restrictPeakFlags) {
		result += " F: " + aPeak.flagsToString();
	}
	if (restrictMultiplicity) {
		result += " C: " + aPeak.c13Multiplicity;
	}
	return result;
}

// Returns a multiplet search query clause for a single Multiplet
function getMultipletQueryClause(aMultiplet, aSpec) {
	"use strict";
	var result,
		settingsKey = "DBSearch/Settings/Multiplet Search/" + (aSpec.dimCount === 2 ? "2D" : "1D"),
		settings = new Settings(settingsKey),
		posTolerance = aSpec.nucleus(1, false) === "1H" ? settings.value("Position/1H", 0.1) : settings.value("Position/Other", 1.0),
		widthTolerance = settings.value("Width", 1.0),
		integralTolerance = settings.value("Integral", 1.0),
		width = aMultiplet.rangeMax - aMultiplet.rangeMin,
		integral = aMultiplet.integralValue();
	result = getPeakQueryInterval("Px:", aMultiplet.delta, posTolerance, true)
		+ getPeakQueryInterval(" Wx: ", width, width * widthTolerance, widthTolerance < 1.0 && !isNaN(width) && width > 0.0)
		+ getPeakQueryInterval(" I: ", integral, integral * integralTolerance, integralTolerance < 1.0 && !isNaN(integral) && integral !== 0.0)
		+ " T: " + aMultiplet.category;
	return result;
}


// Build a peak search query from the given spectrum
function getPeaksQuery(aSpectrum) {
	"use strict";
	var p, peak, includePeak, result, x, y, w,
		searchModes = ["PURITY", "MIXTURE", "COMPOUND", "STANSIM"],   // 0, 1, 2, 3  
		spec = new NMRSpectrum(aSpectrum),
		region = getVisibleRegionPPM(spec),
		allPeaks = spec.peaks(),
		peaks = new Peaks(),
		settingsKey = "DBSearch/Settings/Peak Search/",
		dimKey = (aSpectrum.dimCount === 2 ? "2D" : "1D"),
		settings = new Settings(settingsKey),
		searchMode = searchModes[settings.value(dimKey + "/Scoring", 0)],
		limitToRange = settings.value("limitToRange", false);

	//print(settings.getObject("", {}));
	//print(Peak.peakTypeMap);
	//print(Peak.peakFlagMap);

	// If no peaks found, try to pick some
	if (allPeaks.count === 0) {
		print("No peaks found, trying to pick...");
		allPeaks = new Peaks(spec, getTotalRegionPPM(spec));
	}

	// Filter peaks included in query
	//print("region Dim1: from=" + region.from(1) + " to=" + region.to(1) + " Dim2: from=" + region.from(2) + " to="+ region.to(2));
	for (p = 0; p < allPeaks.count; p++) {
		peak = allPeaks.at(p);
		//print ("peak:" + peak.toString());
		//print("1: r.from=" +  region.from(1) + " r.to=" + region.to(1) + " d=" + peak.delta(1));
		//print("2: r.from=" +  region.from(2) + " r.to=" + region.to(2) + " d=" + peak.delta(2));

		includePeak = false;
		if ((peak.type === Peak.Compound || peak.type === Peak.Impurity) && peak.flagsToString() === "None") {
			includePeak = true;
		}
		if (limitToRange) {
			// Filter peaks by current zoom region
			includePeak = includePeak &&
				isBetween(peak.delta(1), region.from(1), region.to(1)) &&
				(spec.dimCount < 2 || isBetween(peak.delta(2), region.from(2), region.to(2)));
		}
		if (includePeak) {
			peaks.append(peak);
		}
	}

	// Build the peaks query
	result = "{0}".format(peaks.count);

	// Optional: Add the peak search mode - COMPOUND/PURITY/MIXTURE/STANSIM. Default on server side is COMPOUND.
	result += " MODE: " + searchMode;

	// Default settings: Included types Compound+Impurity, Excluded flags All
	result += " inc: Compound|Impurity exc: Hidden|Weak|C13Satellite|Rotational|Labile";

	// Add peak clauses:
	for (p = 0; p < peaks.count; p++) {
		peak = peaks.at(p);
		if (searchMode === "STANSIM") {
			x = getPeakQueryInterval("Px:", peak.delta(1), 0, true);
			w = getPeakQueryInterval("Wx:", peak.width(1), 0, true);
			y = getPeakQueryInterval("I:", peak.intensity, 0, true);
			result += "\n{0} {1} {2} {3}".format(p + 1, x, w, y);
			result += " TT: " + (peak.typeToString() || "None");            // TT is ignored by MnServer, here for debug output
			result += " FF: " + (peak.flagsToString() || "None");           // FF is ignored by MnServer, here for debug output
		} else {
			result += "\n" + (p + 1) + " " + getPeakQueryClause(peak, spec);
		}
	}

	return result;
}

// Build a Multiplet query from the given spectrum.
function getMultipletsQuery(aSpectrum) {
	"use strict";
	var m,
		spec = new NMRSpectrum(aSpectrum),
		multiplets = spec.multiplets(),
		result = "{0}".format(multiplets.count);

	result += " MODE: PURITY";            // Optional: Add the peak search mode - REVERSE/PURITY/MIXTURE. Default is REVERSE.
	for (m = 0; m < multiplets.count; m++) {
		result += "\n" + (m + 1) + " " + getMultipletQueryClause(multiplets.at(m), spec);
	}
	return result;
}

// Retrieve records for all given hits and paste them into Mnova, return list of retrieved molecules
function retrieveHits(aDB, aHits) {
	"use strict";
	var h, aux, items, i,
		//main = mainWindow.activeWindow(),
		//page = main.newPage(),
		docs = [],
		molecules = [];
	for (h = 0; h < aHits.length; h++) {
		aux = mainWindow.newWindow();
		docs.push(aux);
		DBPlugin.getRecord(aDB, aHits.at(h).recordId());
		items = aux.itemCount();
		for (i = 0; i < items; i++) {
			if (aux.item(i).name === "Molecule") {
				//page.addItem(aux.item(i));
				molecules.push(aux.item(i));
			}
		}
	}
	return molecules;
}

// ======================================================================================================

function dbPeakSearchExample() {
	"use strict";
	var query, hits, h,
		db = DBPlugin.client,
		spec = nmr.activeSpectrum(),

		settings = new Settings("DBSearch/Settings"),
		maxHits = settings.value("MaxHits", 10),
		maxRecords = settings.value("MaxRecords", 10),
		minQuality = settings.value("MinHitQuality/PeakSearch", 100),

		// FR #14534: Search only NMR Spectra (not Molecule assignments) iff Search mode is Stans Similarity
		searchModes = ["PURITY", "MIXTURE", "COMPOUND", "STANSIM"],   // 0, 1, 2, 3  
		searchMode = searchModes[settings.value("Peak Search/" + (spec.dimCount === 2 ? "2D" : "1D") + "/Scoring", 0)],
		restrictMethod = (searchMode === "STANSIM") ? "NMR Spectrum" : "",
		restrictField = (searchMode === "STANSIM") ? "Peaks1D" : "";

	// Choose database
	if (!(db.connected() && db.database.length > 0)) {
		mainWindow.doAction("dbDatabaseOpen");
	}
	if (!(db.connected() && db.database.length > 0)) {
		MessageBox.critical("Not connected to database.");
		return;
	}

	query = getPeaksQuery(spec, 1);
	print("Peaks query: " + query);
	hits = DBPlugin.search(db, query, "PEAKLIST1A", restrictMethod, restrictField, maxHits, maxRecords, minQuality);
	print("Peak Hits: " + hits.length);
	for (h = 0; h < hits.length; h++) {
		print("    Hit: " + hits.at(h).toString());
	}


	if (spec.multiplets().count === 0) {
		return;      // Server will throw an exception on query with no clauses. Could do automatic multiplet analysis here.        
	}

	query = getMultipletsQuery(spec, 1);
	print("Multiplet query: " + query);
	hits = DBPlugin.search(db, query, "MULTIPLETLIST1A", "", "", maxHits, maxRecords, settings.value("MinHitQuality/MultipletSearch", 100));
	print("Multiplet Hits: " + hits.length);
	for (h = 0; h < hits.length; h++) {
		print("    Hit: " + hits.at(h).toString());
	}

	//retrieveHits(db, hits);     // Uncomment this line to retrieve records from db to Mnova
	//db.disconnect();
}

// The end.

/******************************************************************************************************
dbSpectrumSearch.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals
		nmr, mainWindow, print, DBPlugin, MessageBox, NMRSpectrum, dbGetNMRPoints */
/*jslint plusplus: true, indent: 4*/

// Retrieve records for all given hits and paste them into Mnova, return list of retrieved molecules
function retrieveHits(aDB, aHits) {
	"use strict";
	var h, aux, items, i,
		//page = main.newPage(),
		docs = [],
		molecules = [];
	for (h = 0; h < aHits.length; h++) {
		aux = mainWindow.newWindow();
		docs.push(aux);
		DBPlugin.getRecord(aDB, aHits.at(h).recordId());
		items = aux.itemCount();
		for (i = 0; i < items; i++) {
			if (aux.item(i).name === "Molecule") {
				//page.addItem(aux.item(i));
				molecules.push(aux.item(i));
			}
		}
	}
	return molecules;
}

// Builds a spectrum similarity query from the given NMR spectrum.
function dbGetSpectrumQuery(aNMRSpectrum) {
	"use strict";
	var pointsJSON, points, query;
	// dbGetNMRPoints(aNMRSpectrum, aDim, aNumBins) from DBPLugin.qs returns JSON string with the fields points, numPoints, numPointsOrig
	pointsJSON = dbGetNMRPoints(aNMRSpectrum, 1, 10);
	points = JSON.parse(pointsJSON);
	//print("Points: " + points);
	query = points;
	query.method = "COSINE";      // Needed: COSINE, TREESIM, STANSIM
	query.itemType = "1D";        // Needed: 1D, 2D, ElViS
	return query;
}

// ======================================================================================================

function dbSpectrumSearchExample() {
	"use strict";
	var query, queryJSON, hits, h,
		db = DBPlugin.client,
		spec = nmr.activeSpectrum();

	if (!db.connected()) {
		MessageBox.critical("Not connected to database.");
		return;
	}

	if (!spec) {
		MessageBox.critical("Need an NMR spectrum for this example..");
		return;
	}

	query = dbGetSpectrumQuery(spec);
	queryJSON = JSON.stringify(query);
	print("Query JSON: " + queryJSON);

	hits = DBPlugin.search(db, queryJSON, "SPECTRUM", "", "", 10, 10, 600);
	print("Hits: " + hits.length);
	for (h = 0; h < hits.length; h++) {
		print("    Hit: " + hits.at(h).toString());
	}

	//retrieveHits(db, hits);     // Uncomment this line to retrieve records from db to Mnova
	// db.disconnect();
}





/******************************************************************************************************
dbTest.qs
Copyright (C) 2009 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided 
AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, 
MERCHANTABILITY AND FITNESSFOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals
	Application, mainWindow, print, DBDefinition, DBPlugin, Dir, File, MessageBox, TextStream, createDatabase
*/

// createDatabase() is defined in dbOpenCreate.qs

// Connection settings used for all test functions
var conn = { host: "localhost", port: 5504, user: "Test", password: "database" };

function dbTest() {
	"use strict";
	var db, dbdef, dbname, dbnames, dbitem, i, items, recid, hits, hit, h,
		dw = mainWindow.activeWindow();
	print(DBPlugin.toString());
	db = DBPlugin.client;
	print(db.toString());

	// Print names of databases on the server
	db.connect(conn.host, conn.port, conn.user, conn.password);
	if (!db.connected()) {
		return MessageBox.critical("Could not connect to database at {0}:{1}.".format(conn.host, conn.port));
	}
	dbnames = db.databases();
	for (i = 0; i < dbnames.length; i += 1) {
		print("  Database {0}: {1}".format(i + 1, dbnames[i]));
	}
	print(dbnames.length + " Databases.");
	db.disconnect();

	// Create a new database
	dbname = createDatabase(conn.host, conn.port, conn.user, conn.password, "test");
	if (!dbname) {
		return MessageBox.critical("Could not create database.");
	}

	// Connect to the newly created database
	db.connect(conn.host, conn.port, conn.user, conn.password, dbname);
	if (!db.connected()) {
		return MessageBox.critical("Could not connect to database {0}'.".format(dbname));
	}

	// Print info about the current database
	dbdef = db.definition(dbname);
	print("Database " + dbdef.name);
	print("   Version: " + dbdef.version);
	print("   Client Version: " + dbdef.clientVersion);
	print("   Server Version: " + dbdef.serverVersion);
	print("   Creator: " + dbdef.creator);
	print("   Created: " + dbdef.created);
	print("   Records: " + dbdef.records);

	try {
		// Save all items in document to a new record
		items = [];
		for (i = 0; i < dw.itemCount(); i += 1) {
			items.push(dw.item(i));
		}
		for (i = 0; i < items.length; i += 1) {
			print(" Item " + i + ": " + items[i]);
		}
		print("Saving...");
		recid = DBPlugin.addRecord(db, items);
		if (recid <= 0) {
			db.disconnect();
			return MessageBox.critical("Error while saving.");
		}
		print("Saved " + items.length + " items under record id " + recid + ".");
		MessageBox.information("Saved " + items.length + " items under record id " + recid + ".");

		// Retrieve saved record and paste into new document
		dw = mainWindow.newWindow();
		print("Retrieving...");
		DBPlugin.getRecord(db, recid);
		print("Pasted " + dw.itemCount() + " items from record id " + recid + ".");
		MessageBox.information("Pasted " + dw.itemCount() + " items from record id " + recid + ".");

		// Retrieve a single molecule and paste into 5th page of new document
		dw = mainWindow.newWindow();
		print("Retrieving...");
		dbitem = DBPlugin.getRecordItem(db, recid, "Molecule", 0, true, 5);
		print(dbitem);
		print("Pasted " + dw.itemCount() + " items from record id " + recid + ".");
		if (dw.itemCount() !== 1) {
			MessageBox.warning("Pasted " + dw.itemCount() + " items from record id " + recid + " but expected 1.");
		}

		// Retrieve a single spectrum and paste into 1st page of new document
		dw = mainWindow.newWindow();
		print("Retrieving...");
		dbitem = DBPlugin.getRecordItem(db, recid, "NMR Spectrum", 2, true, 1);
		print(dbitem);
		print("Pasted " + dw.itemCount() + " items from record id " + recid + ".");
		if (dw.itemCount() !== 1) {
			MessageBox.warning("Pasted " + dw.itemCount() + " items from record id " + recid + " but expected 1.");
		}

		// Do a search
		print("Searching for '-' ...");
		hits = DBPlugin.search(db, "-", "TEXT", "Molecule");
		print(hits.length + " hits found.");
		for (h = 0; h < hits.length; h += 1) {
			hit = hits.at(h);
			print("  Hit {0}: Record={1} Item={2} Score={3} ({4})".format(hit.recordId(), hit.itemId(), hit.score(), hit.toString()));
		}

		// Do a DATETIME search
		print("Searching for items modified on 2020-11-20 ...");
		hits = DBPlugin.search(db, "= 2020-11-20", "DATETIME", "");
		print(hits.length + " hits found.");
		for (h = 0; h < hits.length; h += 1) {
			hit = hits.at(h);
			print("  Hit {0}: Record={1} Item={2} Score={3} ({4})".format(hit.recordId(), hit.itemId(), hit.score(), hit.toString()));
		}

	} catch (e) {
		print(e);
	}

	// Disconnect
	db.disconnect();
	print("All done");
}

function dbTestInteractive() {
	"use strict";
	var db, dbdef;

	db = DBPlugin.client;
	print(db.toString());
	mainWindow.doAction("dbDatabaseOpen");
	print(db.database);
	dbdef = db.definition();
	print(dbdef);
	// Disconnect
	db.disconnect();
	print("All done");
}

function dbTestSchema() {
	"use strict";
	// Create an empty definition:
	var dbdef = DBDefinition.emptyDefinition();
	print(dbdef.toString());

	// Give it a name:
	dbdef.name = "EmptySchema";
	print(dbdef.toString());

	// The same as above in one statement:
	dbdef = DBDefinition.emptyDefinition("EmptySchema");
	print(dbdef.toString());

	// Create a default definition named "NewDatabase":
	dbdef = DBDefinition.defaultDefinition("NewDatabase");
	print(dbdef.toString());

	// Create a custom definition:
	dbdef = DBDefinition.defaultDefinition("MyDatabase");
	dbdef.removeItemType("Mnova");
	dbdef.removeField("Molecule", "Text");
	dbdef.addField("Spectrum", "myField", "TEXT", 100, "=NMRSpectrum(item).experimentType", "The experiment type of the spectrum");
	print(dbdef.toString());
}

function dbTestCreateCustomDatabase(aDatabaseNameStem) {
	"use strict";
	// Create a custom definition:
	var dbdef = DBDefinition.defaultDefinition("");
	dbdef.removeItemType("Mnova");
	dbdef.removeField("Molecule", "Text");
	dbdef.addField("Spectrum", "myField", "TEXT", 100, "=NMRSpectrum(item).experimentType", "The experiment type of the spectrum");
	// Create the database:
	createDatabase(conn.host, conn.port, conn.user, conn.password, aDatabaseNameStem, dbdef);
}

// Save all items in the active document window to the given db. 
// Returns the new record id or 0 for error.
function dbTestStore(aDB) {
	"use strict";
	print("Saving...");
	var i, recid,
		dw = mainWindow.activeWindow(),
		startTime = new Date(),
		items = [];
	for (i = 0; i < dw.itemCount(); i += 1) {
		items.push(dw.item(i));
	}
	recid = DBPlugin.addRecord(aDB, items);
	if (recid > 0) {
		print("Saved " + items.length + " items to record " + recid + " in " + ((new Date() - startTime) / 1000) + " seconds.");
	} else {
		MessageBox.critical("Error while saving.");
	}
	return recid;
}

// Create a new database and store all items in the current document n times into it. Can be used for server stress testing.
function dbTestStoreMany() {
	"use strict";
	var logfile, log, client, dbname, i, startTime, endTime, recid,
		dw = mainWindow.activeWindow(),
		items = dw.selection(),
		n = 1000;

	logfile = new File(Dir.temp() + "/testlog.txt");
	logfile.open(File.WriteOnly);
	log = new TextStream(logfile);

	// What to save
	if (!(items.length > 0)) {
		items = dw.pageItems;
	}
	if (!(items.length > 0)) {
		MessageBox.critical("Nothing to save in current document.");
	}

	// Create a new database
	dbname = createDatabase(conn.host, conn.port, conn.user, conn.password, "C" + n);
	if (dbname === undefined) {
		return MessageBox.critical("Could not create database.");
	}

	// Connect to the newly created database
	client = DBPlugin.createClient();
	client.connect(conn.host, conn.port, conn.user, conn.password, dbname);
	if (!client.connected()) {
		return MessageBox.critical("Could not connect to database '" + dbname + "'.");
	}

	// Save n records
	try {
		startTime = new Date();
		for (i = 1; i <= n; i += 1) {
			print("Saving record " + i + "... ");
			log.write("Saving record " + i + "... ");
			log.flush();
			// Send to db as new record - binary page ids are internally generated from recordid:methodid:itemid
			recid = client.saveRecord(0, items);
			if (recid <= 0) {
				client.disconnect();
				return MessageBox.critical("Error while saving.");
			}
			log.writeln("Saved " + dw.selection().length + " items under record id " + recid + ".");
		}
		endTime = new Date();
		print("Saved " + n + " records in " + ((endTime - startTime) / 1000) + " seconds.");
	} catch (e) {
		print(e);
	}
	// Disconnect
	client.disconnect();
	logfile.close();
	print("All done.");
}

function dbTestDelete() {
	"use strict";
	var
		dbname = "TestDelete",
		client = DBPlugin.createClient();
	client.connect(conn.host, conn.port, conn.user, conn.password, dbname);
	if (!client.connected()) {
		return MessageBox.critical("Could not connect to database '" + dbname + "'.");
	}
	if (client.database !== dbname) {
		return MessageBox.critical("Could not find database '" + dbname + "'.");
	}

	function testDeleteRecords(record_spec) {
		var result;
		print("Deleting record(s) '" + record_spec + "'");
		result = client.deleteRecords(record_spec);
		print("    Result = " + result);
	}

	function testDeleteItems(record_spec, method_spec, item_spec) {
		print("Deleting items '" + item_spec + "' of type '" + method_spec + "' from record(s) '" + record_spec + "'");
		var result = client.deleteItems(record_spec, method_spec, item_spec);
		print("    Result = " + result);
	}

	testDeleteRecords(2);
	testDeleteRecords("3-5,7");
	testDeleteItems(1, "Molecule", 0); // Item number is always 0 for molecules
	testDeleteItems(5, "NMR Spectrum", "1,2");
	testDeleteItems("6", "NMR Spectrum", "");  // Deletes nothing
	testDeleteItems(8, "NMR Spectrum", "1-10");
	testDeleteItems(9, "NMR Spectrum", "0");   // Deletes all NMR spectra from record 9
}

function dbTestReportSearchResults() {
	"use strict";
	var hits, hit, h, tableText,
		db = DBPlugin.client;
	mainWindow.doAction("dbDatabaseOpen");
	print(db.database);

	// Do a search
	print("Searching for '-' ...");
	hits = DBPlugin.search(db, "-", "TEXT", "Molecule");
	print(hits.length + " hits found.");

	// Format hits as html table
	if (hits.length > 0) {
		tableText = '<font style="font-size: 8pt; font-family: Arial; color: black">';
		tableText += '<html><head>';
		tableText += '<title>DB Hits</title>';
		tableText += '</head><body>';
		tableText += '\n<table border="1" cellSpacing="0" cellPadding="4" width="100%">';
		tableText += '\n<tr style="background-color:silver">';
		tableText += '\n  <td><b>Hit</b></td>';
		tableText += '\n  <td><b>Record</b></td>';
		tableText += '\n  <td><b>Item</b></td>';
		tableText += '\n  <td><b>Score</b></td>';
		tableText += '\n  <td><b>Url</b></td>';
		tableText += '</tr>';
		for (h = 0; h < Math.min(hits.length, 30); h += 1) {
			hit = hits.at(h);
			print(" Hit " + h + ": Record=" + hit.recordId() + " Item=" + hit.itemId() + " Score=" + hit.score() + " (" + hit.toString() + ")");
			tableText += '\n<tr>';
			tableText += '\n  <td>' + (h + 1) + '</td>';
			tableText += '\n  <td>' + hit.recordId() + '</td>';
			tableText += '\n  <td>' + hit.itemId() + '</td>';
			tableText += '\n  <td>' + hit.score() + '</td>';
			tableText += '\n  <td>' + hit.toString() + '</td>';
			tableText += '\n</tr>';
		}
		tableText += '</table>';
		tableText += '</body></html>';
		// Draw the html table on current page
		Application.draw.text(tableText, "Report", "DB Hits", true);
	}
}


/******************************************************************************************************
dialogEvent.qs
Copyright (C) 2010 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function EventHandler() {
	this.diag = new Dialog()
	this.diag.title = "My Dialog"
	this.callNumber = 0
}

EventHandler.prototype.onMouseButtonDblClick = function (aJSONString) {
	var aArgument = JSON.parse(aJSONString)
	var actDoc = mainWindow.activeDocument
	if (aArgument.itemId != undefined) {
		var item = actDoc.getItem(aArgument.itemId);
		if (item != undefined) {
			if (item.name == "NMR Spectrum" && aArgument.button == "LeftButton") {
				var nmrItem = new NMRSpectrum(item);
				this.diag.title = this.callNumber + " " + nmrItem.toString()
				this.callNumber++
				return true;
			}
		}
	}
	return false;
}

EventHandler.prototype.onKeyPress = function (aJSONString) {
	var aArgument = JSON.parse(aJSONString)
	var actDoc = mainWindow.activeDocument
	if (aArgument.itemId != undefined) {
		var item = actDoc.getItem(aArgument.itemId);
		if (item != undefined) {
			if (item.name == "NMR Spectrum" && aArgument.key != "Esc") {
				var nmrItem = new NMRSpectrum(item);
				MessageBox.information(this.callNumber + " " + nmrItem.toString() + "\nKey: " + aArgument.key, MessageBox.Ok)
				this.callNumber++
				return true;
			}
		}
	}
	return false;
}

/** Function that creates a dialog that handles events from the GUI
*/
function dialogEvent() {
	Application.eventHandler = new EventHandler()
	Application.eventHandler.diag.show();

	Application.mainWindow.installEventHandler("MouseButtonDblClick", "Application.eventHandler.onMouseButtonDblClick")
	Application.mainWindow.installEventHandler("KeyPress", "Application.eventHandler.onKeyPress")

	while (Application.eventHandler.diag.visible) {
		mainWindow.sleep(1);
		mainWindow.processEvents();
	}
	Application.mainWindow.removeEventHandler("MouseButtonDblClick", "Application.eventHandler.onMouseButtonDblClick")
	Application.mainWindow.removeEventHandler("KeyPress", "Application.eventHandler.onKeyPress")
	Application.eventHandler = undefined
}

/******************************************************************************************************
dialogExample.qs
Copyright (C) 2009 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function showMessage(aMessage) {
	MessageBox.information(aMessage, MessageBox.Ok);
}

function onRadioButtonToggled() {
	if (this.checked)
		showMessage(this.objectName + " " + this.checked);
}

function onPrintLineEditText() {
	showMessage(this.lineEdit.text);
}

function printValue() {
	print("New value: " + this.value);
}

function onComboBoxChanged() {
	print("ComboBox, selected: " + this.currentText);
}

function doOperation() {
	var val1 = this.firstSpinBox.value;
	var val2 = this.secondSpinBox.value;
	print(val1);
	print(val2);
	print(this.operationComboBox.currentText);
	if (this.operationComboBox.currentText == "Sum") {
		var total = val1 + val2;
		showMessage("Sum: " + total);
		print(val1 + val2);
	}
	else if (this.operationComboBox.currentText == "Product") {
		var total = val1 * val2;
		print(val1 * val2);
		showMessage("Product: " + total);
	}
}

function dialogExample() {
	var diag = new Dialog();
	diag.title = "Test Dialog";

	var gBox = new GroupBox();
	gBox.objectName = "groupBox";
	gBox.checkable = true;
	gBox.checked = true;
	gBox.title = "First Group Box";

	var lEditGroupBox = new GroupBox();
	var lEdit = new LineEdit();
	//Setting an object name to the line edit we will be able to recognize this object in the whole program
	lEdit.objectName = "lineEdit";
	lEdit.label = "Add Some Text:";
	lEdit.text = "Some Text";
	var lEditPushButton = new PushButton();
	lEditPushButton.objectName = "lEditPushButton";
	lEditPushButton.text = "Print this text";
	//We connect the clicked event of the push button to the onPrintLineEditText.
	//The first argument of the function connect will we used as "this" object
	lEditPushButton.clicked.connect(lEditGroupBox, onPrintLineEditText);
	lEditGroupBox.add(lEdit, lEditPushButton);
	//when adding a widget to a dialog/group box the widget becomes a property with name widget.objectName of the dialog/goup box
	gBox.add(lEditGroupBox);

	var rButtonGroupBox = new GroupBox();
	rButtonGroupBox.objectName = "rButtonsGroupBox";
	rButtonGroupBox.title = "Radio Buttons Group";
	var rButton1 = new RadioButton();
	rButton1.objectName = "radioButton1";
	rButton1.text = "First";
	rButton1.checked = true;
	//The toggled signal of the Radio Button is emitted when the button changes its toggle state
	//We connect this signal with the onRadionButtonToggled
	rButton1.toggled.connect(rButton1, onRadioButtonToggled);
	rButtonGroupBox.add(rButton1);
	var rButton2 = new RadioButton();
	rButton2.objectName = "radioButton2";
	rButton2.text = "Second";
	rButton2.toggled.connect(rButton2, onRadioButtonToggled);
	//when adding a widget to a dialog/group box the widget becomes a property with name widget.objectName of the dialog/goup box
	rButtonGroupBox.add(rButton2);
	//when adding a widget to a dialog/group box the widget becomes a property with name widget.objectName of the dialog/goup box
	gBox.add(rButtonGroupBox);

	var operationGroupBox = new GroupBox();
	var firstSpinBox = new SpinBox();
	firstSpinBox.objectName = "firstSpinBox";
	firstSpinBox.minimum = 0;
	firstSpinBox.maximum = 10;
	firstSpinBox.value = 5;
	//the valueChanged signal is triggered every time the vale of the spin box changes
	firstSpinBox['valueChanged(int)'].connect(firstSpinBox, printValue);
	var secondSpinBox = new DoubleSpinBox();
	secondSpinBox.objectName = "secondSpinBox";
	secondSpinBox.decimals = 2;
	secondSpinBox.minimum = 0;
	secondSpinBox.maximum = 10;
	secondSpinBox.value = 5;
	secondSpinBox['valueChanged(double)'].connect(secondSpinBox, printValue);
	operationGroupBox.add("First:", firstSpinBox, "Second:", secondSpinBox);
	var pButton = new PushButton();
	pButton.objectName = "pButton";
	pButton.text = "Calculate";
	//we use the operationGroupBox as "this" object in the doOperation to access to all the widgets in the group box
	pButton.clicked.connect(operationGroupBox, doOperation);
	var cBox = new ComboBox();
	cBox.objectName = "operationComboBox";
	cBox.addItem("Sum", "Product");
	print(cBox.items);
	cBox['activated(int)'].connect(cBox, onComboBoxChanged);
	//when adding a widget to a dialog/group box the widget becomes a property with name widget.objectName of the dialog/goup box
	operationGroupBox.add("Operation:", cBox, pButton);
	gBox.add(operationGroupBox);

	diag.add(gBox);

	lEdit.setFocus();

	diag.exec();
	return undefined;
}

function labelTest() {
	var ui = Application.loadUi('<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"><class>Dialog</class><widget class="QDialog" name="Dialog"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>300</height></rect></property><property name="windowTitle"><string>Dialog</string></property><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QLabel" name="label"><property name="text"><string>TextLabel</string></property></widget></item><item><widget class="QDialogButtonBox" name="buttonBox"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="standardButtons"><set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set></property></widget></item></layout></widget><resources/><connections><connection><sender>buttonBox</sender><signal>accepted()</signal><receiver>Dialog</receiver><slot>accept()</slot><hints><hint type="sourcelabel"><x>248</x><y>254</y></hint><hint type="destinationlabel"><x>157</x><y>274</y></hint></hints></connection><connection><sender>buttonBox</sender><signal>rejected()</signal><receiver>Dialog</receiver><slot>reject()</slot><hints><hint type="sourcelabel"><x>316</x><y>260</y></hint><hint type="destinationlabel"><x>286</x><y>274</y></hint></hints></connection></connections></ui>');
	//	var pxm = new Pixmap(":/images/about.png");
	var pxm = new Pixmap();
	pxm.load(":/images/about.png");

	print(pxm.toString());
	ui.widgets.label.pixmap = pxm;
	ui.widgets.label.scaledContents = true;

	var halfPixmap = pxm.scaled(pxm.width / 2, pxm.height / 2);
	print(halfPixmap.toString());

	ui.show()
}

/*******************************************************************************************
dirTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

function dirTest() {
	var d = new Dir(Dir.home());
	print(d);
	print(Dir.home());
	print(Dir.current());
	print(Dir.root());
	print(Dir.temp());
	print(Dir.application());
	print(Dir.drives());
	print(Dir.cleanDirPath("c:///temp\\\\\\"));
	print(Dir.convertSeparators("c:/temp\\test"));

	d = new Dir(Dir.application());
	print(d);

	var d1 = new Dir(d);
	print("d1: ", d1);

	print("scripts directory exists: " + d.fileExists("scripts"));
	d.cd("scripts");
	print(d);
	d.cdUp();
	print(d);

	print(d.entryList("*.dll", Dir.Files, Dir.Size));

	print(d.filePath("test.txt"));

	var d = new Dir(Dir.temp());
	print(d);
	d.mkdir("MNova_QtScript_Test_Dir");
	d.cd("MNova_QtScript_Test_Dir");
	print(d);
	d.cdUp();

	d.mkpath("MNova_QtScript_Test_Dir_1/2/3/4");
	d.cd("MNova_QtScript_Test_Dir_1/2/3/4");
	print(d);

	d.cdUp();
	d.rmdir("4");
	print(d.cd("4"));
	d.cd("../../..");
	print(d);
	print(d.rmpath("MNova_QtScript_Test_Dir_1/2/3"));

	d.mkpath("MNova_QtScript_Test_Dir_2/2/3/4");
	if (d.rename("MNova_QtScript_Test_Dir_2", "MNova_QtScript_Test_Dir_3"))
		print("Directory {0}2 renamed to {0}3".format("MNova_QtScript_Test_Dir_"));
	d.rmpath("MNova_QtScript_Test_Dir_3/2/3/4");

	print(Dir.current());
	Dir.setCurrent(Dir.temp());
	print(Dir.current());
}

/******************************************************************************************************
doActionTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function doActionTest() {
	mainWindow.doAction("nmrAutoPeakPicking");
	//mainWindow.doAction("action_Edit_Delete");
}
/* documentTestSimple.qs
opens all the spectra in one directory, stacks them and shows the result */
function documentTestSimple() {
	var dirPath = FileDialog.getExistingDirectory(Dir.home(), "Open Directory"),
		dir, innerDirs,
		nmrItems, arrItem, doc,
		i, nmrPages = [], start, end;

	if (dirPath) {
		dir = new Dir(dirPath);
		innerDirs = dir.entryList("*", Dir.Dirs | Dir.NoDotAndDotDot, Dir.Name)
	}
	if (innerDirs.length === 0) {
		return;
	}
	innerDirs.sort(Dir.alphanumericPathsCompare)
	for (i = 0; i < innerDirs.length; ++i) {
		innerDirs[i] = dir.absPath + "/" + innerDirs[i];
	}

	function open(aDoc) {
		mainWindow.setBusy("Opening")
		serialization.importFile(innerDirs, "", aDoc);
		nmrItems = aDoc.itemsByName('NMR Spectrum');
		if (nmrItems.length !== innerDirs.length) {
			MessageBox.critical("Unable to open all the spectra");
			return;
		}
		for (i = 0; i < nmrItems.length; ++i) {
			nmrPages.push(nmrItems[i].page);
		}
		arrItem = nmr.createArrayedItem(nmrItems, true);
		aDoc.deletePages(nmrPages);
		mainWindow.endBusy();
	}

	function runNew() {
		doc = new Document();
		pag = new Page(doc.newPage());
		print("Page valid {0}".format(pag.isValid()));
		Application.lockDocument(doc);
		open(doc);
		serialization.save("/tmp/MyDoc.mnova", "mnova");
		mainWindow.addDocument(doc);
		//		doc.destroyDocument();
		Application.unlockDocument();
	}

	start = new Date();
	print(start.toLocaleTimeString());
	runNew();
	start = new Date();
	print(start.toLocaleTimeString());
}

/******************************************************************************************************
drawingObjects.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function drawingObjects() {
	var w = new DocumentWindow(mainWindow.activeWindow());
	var p = new Page(w.curPage());

	var text = draw.text("<b>This is text</b>", true);
	text.translate(200, 200);
	text.color = "cyan";
	print(text);
	print(text.plainText);

	var rect = draw.rectangle(p.width / 3, p.height / 3);
	rect.translate(50, 75);
	rect.angle = 45;
	rect.color = "red";
	rect.opacity = 50;
	print(rect);

	var arrow = draw.arrow(p.right, p.top, p.left, p.bottom, false, true);
	arrow.startX = (p.right + p.left) / 2.0;
	arrow.startY = p.top + 100;
	arrow.lineColor = "blue";
	arrow.lineStyle = PageItem.DashLine;
	print(arrow);

	var ellipse = draw.ellipse(p.width / 2, p.height / 2);
	ellipse.angle = 90;
	ellipse.lineStyle = PageItem.DashDotLine;
	//ellipse.color = "pink";
	print(ellipse);

	w.update();
}
/******************************************************************************************************
eventHandlerExample.qs
Copyright (C) 2010 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

//! Multiplet Changed Event, the argument will define the itemId and the multipletId
function onMultipletChanged(aJSONString) {
	var info = JSON.parse(aJSONString); //this constructs the argument object parsing the JSON string sent as parameter
	MessageBox.information("Multiplet changed: " + aJSONString, MessageBox.Ok)
	return true;
}
Application.mainWindow.installEventHandler("nmrMultipletChanged", "onMultipletChanged")

//! Multiplet Selected Event, the argument will define the itemId and the multipletId
function onMultipletClicked(aJSONString) {
	var info = JSON.parse(aJSONString);//this constructs the argument object parsing the JSON string sent as parameter
	print("Multiplet Clicked: " + aJSONString)
	return true;
}
Application.mainWindow.installEventHandler("nmrMultipletClicked", "onMultipletClicked")

//! Multiplet Highlighted Event, the argument will define the itemId and the multipletId
function onMultipletHighlighted(aJSONString) {
	var info = JSON.parse(aJSONString);//this constructs the argument object parsing the JSON string sent as parameter
	print("Multiplet Highlighted: " + JSON.stringify(aInfo))
	return true;
}
//Application.mainWindow.installEventHandler("nmrMultipletHighlighted","onMultipletHighlighted")


//! Integral Changed Event, the argument will define the itemId and the integralId
function onIntegralChanged(aJSONString) {
	var info = JSON.parse(aJSONString)//this constructs the argument object parsing the JSON string sent as parameter
	MessageBox.information("Integral changed: " + aJSONString, MessageBox.Ok)
	return true;
}
Application.mainWindow.installEventHandler("nmrIntegralChanged", "onIntegralChanged")

//! Assignment, the argument will define the spectrumId, the moleculeId, the atomNumber, the shiftMax and shiftMin
function onAssignment(aJSONString) {
	var info = JSON.parse(aJSONString)//this constructs the argument object parsing the JSON string sent as parameter
	MessageBox.information("onAssignment: " + aJSONString, MessageBox.Ok)
	return true;
}
Application.mainWindow.installEventHandler("nmrAssignmentMade", "onAssignment")

//! Assignment Highlighted, the argument will define the spectrumId, the moleculeId, the atomNumber, the shiftMax and shiftMin
function onAssignmentHighLighted(aJSONString) {
	var info = JSON.parse(aJSONString)//this constructs the argument object parsing the JSON string sent as parameter
	print("HIGHLIGHT: " + aJSONString)
	return true;
}
//Application.mainWindow.installEventHandler("nmrAssignmentHighlighted", "onAssignmentHighLighted")

//! NMR Spectrum Imported Event, the argument contains the itemId
function onNMRSpectrumImported(aJSONString) {
	print("onNMRSpectrumImported " + aJSONString)
	var info = JSON.parse(aJSONString)//this constructs the argument object parsing the JSON string sent as parameter
	MessageBox.information(aJSONString, MessageBox.Ok)
	return true;
}
Application.mainWindow.installEventHandler("nmrSpectrumImported", "onNMRSpectrumImported")

//! DB Items Pasted Event, the argument is an array with the itemIds of the pasted items
function onDBItemsPasted(aJSONString) {
	print("onDBItemsPasted " + aJSONString)
	var info = JSON.parse(aJSONString)//this constructs the argument object parsing the JSON string sent as parameter
	//MessageBox.information(aJSONString, MessageBox.Ok)
	var msg = "Pasted " + info.length + " items:";
	for (var i = 0; i < info.length; i++) msg += "\n  Id=" + info[i];
	MessageBox.information(msg, MessageBox.Ok)
	return true;
}
Application.mainWindow.installEventHandler("dbItemsPasted", "onDBItemsPasted")

/** Example function to handle mouse button double click events. Return false to let Mnova handle the event. Mnova will call this function with one argument with these properties: 
	- itemId:String. Acctive item id, might be undefined
	- x:Number. X coordinate in canvas units
	- y:Number. Y coordinate in canvas units 
	- button:String. The button pressed: "LeftButton","RightButton" or undefined
*/
function onMouseButtonDoubleClick(aJSONString) {
	var aArgument = JSON.parse(aJSONString)//this constructs the argument object parsing the JSON string sent as parameter
	var actDoc = mainWindow.activeDocument
	if (aArgument.itemId !== undefined) {
		var item = actDoc.getItem(aArgument.itemId);
		if (item != undefined) {
			if (item.name == "NMR Spectrum" && aArgument.button == "LeftButton") {
				var nmrItem = new NMRSpectrum(item);
				MessageBox.information(nmrItem.toString() + "\nSpectrum Index: " + nmrItem.curSpecIndex + "\nPos: " + aArgument.x + " " + aArgument.y, MessageBox.Ok)
				return true;
			}
		}
	}
	return false;
}
Application.mainWindow.installEventHandler("MouseButtonDblClick", "onMouseButtonDoubleClick")

/** Example function to handle mouse move events. Return false to let Mnova handle the event. Mnova will call this function with one argument with these properties: 
	- itemId:String. Acctive item id, might be undefined
	- x:Number. X coordinate in canvas units
	- y:Number. Y coordinate in canvas units 
*/
function onMouseMove(aJSONString) {
	var aArgument = JSON.parse(aJSONString)//this constructs the argument object parsing the JSON string sent as parameter
	if (aArgument.button == "LeftButton")
		print("Mouse Move: ", aArgument.x, aArgument.y);
	return false;
}
//Application.mainWindow.installEventHandler("MouseMove", "onMouseMove")

/** Example function to handle key press events. Return false to let Mnova handle the event. Mnova will call this function with one argument with these properties: 
	- itemId:String. Acctive item id, might be undefined
	- key:String. Key pressed with modificators, e.g. "C", "Ctrl+G", "Shift+U", "Alt+I"
*/
function onKeyPress(aJSONString) {
	var aArgument = JSON.parse(aJSONString)//this constructs the argument object parsing the JSON string sent as parameter
	var actDoc = mainWindow.activeDocument
	if (aArgument.itemId !== undefined) {
		var item = actDoc.getItem(aArgument.itemId);
		if (item != undefined) {
			if (item.name == "NMR Spectrum" && aArgument.key != "Esc") {
				var nmrItem = new NMRSpectrum(item);
				MessageBox.information(nmrItem.toString() + "\nKey: " + aArgument.key, MessageBox.Ok)
				return true;
			}
		}
	}
	return false;
}
Application.mainWindow.installEventHandler("KeyPress", "onKeyPress")

/** Example function to handle selectionChanged event. Return true to avoid propagation of the event. If the selection is empty aJSONString will be empty. Mnova will call this function with one argument with these properties: 
	- activeId:String. Acctive item id.
	- selectionIds: Array. Ids of all the item selected.
Besides this properties, an array with the item ids of the same type will be added under a property named with the item name ("NMR Spectrum", "Molecule", ...)
*/
function onSelectionChanged(aJSONString) {
	'use strict';
	if (aJSONString) {
		try {
			var value = JSON.parse(aJSONString);
			print(JSON.stringify(value));
			if (value['NMR Spectrum']) {
				print("Selection has NMR");
			}
		} catch (er) {
			print(er);
		}
	} else {
		print("Empty Selection");
	}
}
Application.mainWindow.installEventHandler("selectionChanged", "onSelectionChanged");



/*******************************************************************************************
extractNMRTrace.qs
Copyright (C) 2012 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

function extractNMRTrace() {
	var spec = new NMRSpectrum(nmr.activeSpectrum())
	if (spec.isValid()) {
		var trace = spec.extractInnerTrace("horizontal", "sum")
		print(trace)
	}
}

/******************************************************************************************************
fidTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function fidTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	print(spec.fidImag(0));
	if (spec.fidSetImag(0, 0))
		print(spec.fidImag(0));
	print(spec.fidReal(0));
	if (spec.fidSetReal(0, 0))
		print(spec.fidReal(0));
	spec.process();
	mainWindow.activeWindow().update();
}
/*******************************************************************************************
fileDialogTest.qs
Copyright (C) 2011 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

function getSaveFileNameTest() {
	var fn = FileDialog.getSaveFileName(); // No parameters
	print(fn);

	fn = FileDialog.getSaveFileName("Spectra (*.spc);;Molecules (*.mol)"); // File filter parameter
	print(fn);

	fn = FileDialog.getSaveFileName("Spectra (*.spc);;Molecules (*.mol)", "Save Your Data"); // File filter and dialog name parameters
	print(fn);

	fn = FileDialog.getSaveFileName("", "", Dir.temp()); // Empty file filter and dialog name parameters, and start directory parameter
	print(fn);

	fn = FileDialog.getSaveFileName("*.txt*", "", Dir.temp(), 4); //Don´t ask for confirmation
	print(fn);

	fn = FileDialog.getSaveFileName("*.txt*", "", Dir.temp(), 0);//Asks for confirmation
	print(fn);
}

function getOpenFileNameTest() {
	var fn = FileDialog.getOpenFileName(); // No parameters
	print(fn);

	fn = FileDialog.getOpenFileName("Spectra (*.spc, *.nmr, *.fid);;Molecules (*.mol)"); // File filter parameter
	print(fn);

	fn = FileDialog.getOpenFileName("Spectra (*.spc);;Molecules (*.mol)", "Open Your Data"); // File filter and dialog name parameters
	print(fn);

	fn = FileDialog.getOpenFileName("", "", Dir.temp()); // Empty file filter and dialog name parameters, and start directory parameter
	print(fn);
}

function getOpenFileNamesTest() {
	var fn = FileDialog.getOpenFileNames(); // No parameters
	print(fn);

	fn = FileDialog.getOpenFileNames("Spectra (*.spc, *.nmr, *.fid);;Molecules (*.mol)"); // File filter parameter
	print(fn);

	fn = FileDialog.getOpenFileNames("Spectra (*.spc);;Molecules (*.mol)", "Open Your Data"); // File filter and dialog name parameters
	print(fn);

	fn = FileDialog.getOpenFileNames("", "", Dir.temp()); // Empty file filter and dialog name parameters, and start directory parameter
	print(fn);
}

function getExistingDirectoryTest() {
	var dn = FileDialog.getExistingDirectory();
	print(dn);

	dn = FileDialog.getExistingDirectory(Dir.temp());
	print(dn);

	dn = FileDialog.getExistingDirectory(Dir.home(), "Select Directory");
	print(dn);
}

function fileDialogTest() {
	getSaveFileNameTest();
	getOpenFileNameTest();
	getOpenFileNamesTest();
	getExistingDirectoryTest();
}
/******************************************************************************************************
fileSystemWatcherTest.qs
Copyright (C) 2012 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals FileDialog, FileSystemWatcher, Application, Dir, print*/
/*jslint plusplus: true, indent: 4, continue: true, bitwise: true*/

function fileSystemWatcherTest() {
	'use strict';
	var ui = '<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"><class>Dialog</class><widget class="QDialog" name="Dialog"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>300</height></rect></property><property name="windowTitle"><string>Dialog</string></property><layout class="QGridLayout" name="gridLayout"><item row="3" column="0" colspan="3"><widget class="QPlainTextEdit" name="plainTextEdit"/></item><item row="4" column="2"><widget class="QPushButton" name="cancelButton"><property name="text"><string>&amp;Cancel</string></property></widget></item><item row="2" column="2"><widget class="QPushButton" name="removePushButton"><property name="text"><string>&amp;Remove</string></property></widget></item><item row="2" column="0"><spacer name="horizontalSpacer_2"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item><item row="0" column="0" colspan="3"><widget class="QListWidget" name="listWidget"/></item><item row="2" column="1"><widget class="QPushButton" name="addPushButton"><property name="text"><string>&amp;Add</string></property></widget></item><item row="4" column="0" colspan="2"><spacer name="horizontalSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item></layout></widget><resources/><connections><connection><sender>cancelButton</sender><signal>clicked()</signal><receiver>Dialog</receiver><slot>reject()</slot><hints><hint type="sourcelabel"><x>370</x><y>283</y></hint><hint type="destinationlabel"><x>287</x><y>277</y></hint></hints></connection></connections></ui>';

	var opts = {};
	opts.dialog = Application.loadUi(ui);
	opts.watcher = new FileSystemWatcher();
	opts.watcher.ignoreOld = false;
	opts.watcher.maxDepth = 1;
	opts.watcher.filters = Dir.Dirs | Dir.Files;
	//opts.watcher.nameFilters = ['fid'];
	opts.dialog.widgets.removePushButton.enabled = false;

	//explicitly check the changed files every minute
	//opts.watcher.timeOutMinutes = 1;

	//disable the OS file watcher, when you want to use only the timeOutMinutes
	//opts.watcher.useSystemBackend = false;

	//ignore the files already present in the directories
	opts.watcher.ignoreOld = true;

	//how depth looks for changed files
	opts.watcher.maxDepth = 2;

	// Fast hash calculation. True by default, uses modification date and size to check for modifications
	// if false it uses only the modification date reported by the file system.
	opts.watcher.useFastHash = false;

	//ignore files and directories older than X days. -1 to use all files and directories
	opts.watcher.maxOldDays = -1;

	//use multi thread
	opts.watcher.useMultiThread = true;

	opts.watcher.directoryChangedExt.connect(opts, fileSystemWatcherTest.onDirectoryChanged);
	opts.dialog.rejected.connect(opts, fileSystemWatcherTest.onCancel);
	opts.dialog.widgets.listWidget.itemSelectionChanged.connect(opts, function () {
		var sel = this.dialog.widgets.listWidget.selection;
		this.dialog.widgets.removePushButton.enabled = sel.length;
	});
	opts.dialog.widgets.removePushButton.clicked.connect(opts, function () {
		var sel = this.dialog.widgets.listWidget.selection,
			i;
		for (i = 0; i < sel.length; ++i) {
			print("Remove %1".arg(sel[i].text));
			this.watcher.removePath(sel[i].text);
		}
		this.dialog.widgets.listWidget.items = this.watcher.paths;
	});
	opts.dialog.widgets.addPushButton.clicked.connect(opts, function () {
		var dir = FileDialog.getExistingDirectory(Dir.home(), "Select Directory to Watch");
		this.watcher.addPath(dir);
		this.dialog.widgets.listWidget.items = this.watcher.paths;
	});

	// handle start/end cache making
	opts.watcher.cacheStart.connect(opts.dialog, function () {
		var now = new Date();
		this.widgets.plainTextEdit.clear();
		this.widgets.plainTextEdit.appendPlainText("[%1] Cache Start".arg(now.toISOString()));
	});

	opts.watcher.cacheEnd.connect(opts.dialog, function () {
		var now = new Date();
		this.widgets.plainTextEdit.appendPlainText("[%1] Cache End".arg(now.toISOString()));
	});

	// handle system add sub dirs
	opts.watcher.systemAddSubDirsStart.connect(opts.dialog, function () {
		var now = new Date();
		this.widgets.plainTextEdit.appendPlainText("[%1] System Add Sub Dirs Start".arg(now.toISOString()));
	});

	opts.watcher.systemAddSubDirsEnd.connect(opts.dialog, function () {
		var now = new Date();
		this.widgets.plainTextEdit.appendPlainText("[%1] System Add Sub Dirs End".arg(now.toISOString()));
	});

	// cache progress notifications
	// this field controls how many levels of notifications we want
	// the bigger the level the poorest the performance but the information is more relevant.
	// -1 disable the notifications
	opts.watcher.maxNotifyDepth = 3;
	// aTxt is the name of a directory that was just added to the cache
	opts.watcher.directoryAddedToCache.connect(opts.dialog, function (aTxt) {
		this.widgets.plainTextEdit.appendPlainText("[ADDED] %1".arg(aTxt));
	});

	opts.dialog.show();
}

fileSystemWatcherTest.onDirectoryChanged = function (aPath, aArray) {
	'use strict';
	var txt = '', template = "[%1] %2\n", i;
	for (i = 0; i < aArray.length; ++i) {
		txt += template.arg(aPath).arg(aArray[i]);
		//		txt += aArray[i]+"\n";
	}
	this.dialog.plainTextEdit.appendPlainText(txt);
	// this.dialog.plainTextEdit.plainText += txt;
	if (aArray.length) {
		print(txt);
	}
};

fileSystemWatcherTest.onCancel = function () {
	'use strict';
	this.watcher.directoryChangedExt.disconnect(this, fileSystemWatcherTest.onDirectoryChanged);
	this.watcher.deleteLater();
	this.watcher = undefined;
};

/*******************************************************************************************
fileTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/
function absDirPathText() {
	fn = Dir.temp() + "/MNova_File_Test.txt";
	print(fn);
	print(File.absDirPath(fn));

	var f = new File(fn);
	f.open(File.WriteOnly);
	f.close();
	print(f);
	print(f.absDirPath);
	f.remove();
}

function fileTest() {
	fn = Dir.temp() + "/MNova_File_Test.txt";
	var f = new File(fn);
	print(f);

	f1 = f;
	print(f1);

	var f2 = new File(f);
	print(f2);

	f.open(File.WriteOnly); // The way to create a file
	print(f);
	print(f1);
	print(f2);

	f.close();
	print(f);

	f.remove();
	print(f);

	File.create(fn);
	File.rename(fn, fn + ".1");
	File.remove(fn);
	f = new File(fn + ".1");
	print(f);
	File.remove(fn + ".1");
	print(f);

	Dir.setCurrent(Dir.temp());
	f.name = "MNova_File_Test_2.txt";
	print(f);
	f.open(File.WriteOnly);
	print(f);
	f.close();
	f.remove();
	print(f);
}

/******************************************************************************************************
fitRegionsTest.qs
Copyright (C) 2010 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
//! Print the fit regions
function fitRegionsTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());

	var fitList = spec.fitRegions();
	print(fitList);
	for (var i = 0; i < fitList.length; i++) {
		var peakList = fitList[i].peaks;
		print(fitList[i].name);
		for (var j = 0; j < peakList.length; j++) {
			print(peakList[j]);
		}
	}

	mainWindow.activeWindow().update();
}

//! Run fitting
function lineFittingTest() {
	//get the current spectrum
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	if (spec.isValid() == false)
		throw ("Invalid Spectrum");

	//check the options
	var p = new NMRProcessing(spec.proc);
	print(p.getParameter("Fitting"));
	//modify the number of iterations
	p.setParameter("Fitting.maxIt", 200);
	//locks the shape by default, set to 0 to unlock all
	p.setParameter("Fitting.DefaultLocks", 8)
	print(p.getParameter("Fitting"));
	spec.proc = p;

	//create a region using an spectrum region, the peaks will be detected in the spectrum
	var reg = new FitRegion(5.7, 6.0, spec);
	reg.name = "Reg1";
	print(reg);
	print(reg.peaks)

	//Fit the regions and add them to the spectrum
	var regionList = []
	regionList.push(spec.fit(reg, true)); //spec.fit(reg,true); will return a new fitted region. Setting the second parameter to false will hide the fit dialog
	print(regionList);

	spec.setFitRegions(regionList);
	spec.update();
	mainWindow.activeDocument.update();
}
/******************************************************************************************************
graphModelTest.qs
Copyright (C) 2012 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
function yModelTest() {
	var yModel = new GraphYModel(GraphYModel.emConcentration, 1, 2)
	print(yModel)
	yModel.f1From = 1.2
	print(yModel.f1From)
}

function fitModelTest() {
	//var fit = new FitModel(GraphFitModel.FirstOrder)
	//print(fit)

	var customParams = new Object();
	customParams.A = 1
	customParams.B = 0
	var customFit = new GraphFitModel('A*x+B', customParams)
	print(customFit)
}

function responseFactorTest() {
	var funcObj = new Object()
	funcObj.formula = "y*M/k"
	funcObj.params = { M: 10, k: 3 }
	var rFactor = new GraphResponseFactor(GraphResponseFactor.Formula, funcObj)
	//	var rFactor = new ResponseFactor(ResponseFactor.Concentration,2.0)
	//	rFactor.units = "µM"
	//	var rFactor = new ResponseFactor(ResponseFactor.PULCON,10.0)
	print(rFactor)
}
/******************************************************************************************************
graphReportTest.qs
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals Env, draw, mainWindow, qsTr, Settings, Application, GraphReporterBase*/
/*jslint plusplus: true, indent: 4, loopfunc: true*/

function GraphReporterTest() {
	"use strict";

	this.fName = "Report Fit Parameters";
}

GraphReporterTest.prototype = new GraphReporterBase();

GraphReporterTest.prototype.report = function (aGraph, aCreateItem, aHtml, aSettings) {
	'use strict';
	var sCount, s, fitModels, yModels, reportText, graphProperties, horzAxsLabel,
		yModelLabel, formula, parameters, template, parametersStr, p, parameterTemplate,
		htmlTemplate, reportParamTemplate, reportParams;

	if (aGraph === undefined || !aGraph.isValid()) {
		throw new Error("Invalid Graph");
	}

	htmlTemplate = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><title>Graph Report</title></head><body>%1</body></html>"; //%1 html body
	if (aHtml) {
		template = "<p>%1</p>"; //%1: label, %2: formula, %3: parameters, %4: comments
		parameterTemplate = '<p>%1=%2</p>'; //%1: name, %2: value
		reportParamTemplate = "<p>%1(%2)=%3</p>"; //%1: name, %2: formula, %3 value
	} else {
		template = "%1\n";
		parameterTemplate = '%1=%2\n'; //%1: name, %2: value
		reportParamTemplate = "%1(%2)=%3\n"; //%1: name, %2: formula, %3 value
	}

	reportText = '';
	sCount = aGraph.seriesCount;
	fitModels = aGraph.fitModels;
	yModels = aGraph.yModels;
	graphProperties = aGraph.graphicProperties;
	horzAxsLabel = graphProperties.horzAxis.label;
	horzAxsLabel = horzAxsLabel.replace(/\([\w\W]*\)/, '');
	for (s = 0; s < sCount; ++s) {
		yModelLabel = yModels[s].label;
		if (yModelLabel.length === 0) {
			if (s === 0) {
				yModelLabel = 'Y';
			} else {
				yModelLabel = 'Y%1'.arg(s);
			}
		}
		formula = fitModels[s].formula;
		if (formula.length !== 0) {
			formula = formula.replace(/exp/g, 'EXP');
			formula = formula.replace(/x/g, horzAxsLabel);
			formula = formula.replace(/EXP/g, 'exp');
			parameters = fitModels[s].fitParams;
			parametersStr = '';
			Object.keys(parameters).forEach(function (p) {
				if (parametersStr.length !== 0) {
					parametersStr += '\n';
				}
				parametersStr += parameterTemplate.arg(p).arg(parameters[p].toPrecision(aSettings.fDecimals));
			});
			parameters = fitModels[s].reportParams;
			Object.keys(parameters).forEach(function (p) {
				if (parametersStr.length !== 0) {
					parametersStr += ' ';
				}
				parametersStr += reportParamTemplate.arg(p).arg(parameters[p].Formula).arg(parameters[p].Value.toPrecision(aSettings.fDecimals));
			});
			// reportText += template.arg(yModelLabel).arg(formula).arg(parametersStr).arg(fitModels[s].error.toPrecision(precision));
			reportText += template.arg(parametersStr);
		}
	}
	if (aHtml) {
		reportText = htmlTemplate.arg(reportText);
	}
	if (aCreateItem) {
		draw.text(reportText, "Report Special", "Graph", true, aGraph.uuid);
	}
	return reportText;
};

Env.GraphReporters.push(new GraphReporterTest());

/******************************************************************************************************
import_process_save_loop.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
// This example function demonstrates how to apply some processing to a set of spectral files and to save the result in the different file formats.
function import_process_save_loop() {
	var dirName = "c:/spectra"; // Source directory with spectra to be processed.
	var resultDirName = dirName; // Destination directory where processed spectra should be put.
	var procName = "c:/temp/proc.mnp"; // Processing file. It must be created in the Processing Template dialog of MestReNova.
	var fileMask = "fid"; // This mask specifies files to be processed. 
	var dirMask = "*.fid"; // This mask specifies directories to be scanned for spectra.

	var dir = new Dir(dirName);
	if (!dir.exists) {
		MessageBox.critical("Directory " + dirName + " does not exist.", MessageBox.Ok);
		return;
	}
	dir.cdUp();

	// The below function getMaskFiles is located in the files.qs script. 
	var files = getMaskFiles(dirName, dir.absPath, fileMask, dirMask, true);
	for (var i = 0; i < files.length; i++) {
		var dw = new DocumentWindow(Application.mainWindow.newWindow()); // Create new document window
		if (serialization.open(files[i])) {
			nmr.process(procName);
			var toReplace = new RegExp("[/|:]", "g");
			fileName = resultDirName + "/" + files[i].replace(toReplace, "_"); // Generate a filename for processed spectrum. 
			serialization.save(fileName + ".mnova", "mnova");	// MestReNova file format
			serialization.save(fileName + ".pdf", "pdf"); // Adobe PDF file format
			serialization.save(fileName + ".txt", "ascii"); // ASCII
			print(fileName); // Prints file name in the debug window
		}
		dw.close(); // Close document window of processed spectrum
	}
}

/******************************************************************************************************
import_process_saveOneAscii_loop.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
// This example function demonstrates how to apply some processing to a set of spectral files and to save the result in a single ASCII file.
/*jslint plusplus: true*/
/*global FileDialog, settings, TextStream, Dir, File, nmr, serialization, getMaskFiles, Application, NMRSpectrum, mainWindow*/


function import_process_saveOneAscii_loop() {
	"use strict";

	var procName, fileMask, dirMask, specDirKey, dirName, dir, outDirKey, saveDir, spec, fileName, fout, sout, lastOutName, files, fi, dw, flastOut, slastOut, si, ppm, dPpm, length;

	procName = "c:/procTemplates/proc.mnp"; // Processing file. It must be created in the Processing Template dialog of MestReNova.
	fileMask = "fid"; // This mask specifies files to be processed.
	dirMask = "*"; // This mask specifies directories to be scanned for spectra.

	// Select a directory with spectral data
	specDirKey = "import_process_saveOneAscii_loop/SpectraDir";
	dirName = FileDialog.getExistingDirectory(settings.value(specDirKey, Dir.home()), "Select Spectra Directory");

	if (!dirName) {
		return;
	}
	settings.setValue(specDirKey, dirName); // Save the directory name to be used another time the script is called

	dir = new Dir(dirName);
	dir.cdUp();

	// Select a file to save the output
	outDirKey = "import_process_saveOneAscii_loop/OutputDir";
	saveDir = settings.value(outDirKey, Dir.home()); // Get last used directory name
	fileName = FileDialog.getSaveFileName("ASCII Files (*.txt)", "Select Output File", saveDir);

	if (!fileName) {
		return;
	}

	// Open the selected file and create a text stream mapped to it
	fout = new File(fileName);
	settings.setValue(outDirKey, fout.absDirPath); // Save the directory name to be used another time the script is called
	sout = new TextStream(fout);
	sout.precision = 10;

	// Temporary file name
	lastOutName = Dir.temp() + "/import_process_saveOneAscii_loop.lastOut.tmp";
	if (File.exists(lastOutName)) {
		File.remove(lastOutName);
	}

	// The below function getMaskFiles is located in the files.qs script.
	files = getMaskFiles(dirName, dir.absPath, fileMask, dirMask, true);
	files.sort(Dir.numericPathsCompare);

	for (fi = 0, length = files.length; fi < length; fi++) {

		dw = mainWindow.newWindow(); // Create new document window
		if (serialization.open(files[fi])) {

			nmr.process(procName); // Apply processing template
			spec = new NMRSpectrum(nmr.activeSpectrum());

			fout.open(File.WriteOnly);

			flastOut = new File(lastOutName);
			slastOut = new TextStream(flastOut);
			if (!fi) {
				// Put fist column of the file in ppm. The scale is taken from the first spectrum.
				flastOut.open(File.WriteOnly);
				slastOut.precision = 10;

				ppm = spec.hz() / spec.frequency();
				dPpm = spec.scaleWidth() / spec.count() / spec.frequency();
				for (si = spec.count() - 1; si >= 0; si--) {
					slastOut.write(ppm, "\n");
					ppm += dPpm;
				}
				flastOut.close();
			}
			flastOut.open(File.ReadOnly);

			for (si = spec.count() - 1; si >= 0; si--) {
				sout.write(slastOut.readLine(), "\t\t", spec.real(si), "\n");
			}

			fout.close();
			flastOut.close();
			flastOut.remove();
			if (fi < length - 1) {
				File.copy(fileName, lastOutName);
			}
		}
		dw.close(); // Close document window of processed spectrum
	}
}

/******************************************************************************************************
integralTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function integralTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	//Copy spectrum integrals
	var intList = new Integrals(spec.integrals());
	print(intList);
	print(intList.count);
	print(intList.normValue);

	//Copy one integral
	var myInt = new Integral(intList.at(0));
	print(myInt);
	print(myInt.rangeMax(1));
	print(myInt.rangeMin(1));
	if (spec.dimCount > 1) {
		print(myInt.rangeMax(2));
		print(myInt.rangeMin(2));
	}
	print("Integral Value " + myInt.integralValue());
	print("Normalized value " + myInt.integralValue(intList.normValue));

	//Create and add new integral
	var sReg = new SpectrumRegion(7.0, 7.5);
	var newInt = new Integral(spec, sReg, false);
	print(newInt);
	print(newInt.integralValue());
	intList.append(newInt);
	//Modify integrals normalization
	intList.normValue = newInt.integralValue();

	//Replace spectrum integrals
	spec.setIntegrals(intList);
	spec.process();
}
/******************************************************************************************************
itempos.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function itemPos() {
	var w = new DocumentWindow(mainWindow.activeWindow());
	var p = new Page(w.curPage());
	var c = p.itemCount();
	var i = 0;
	var itemArray = new Array(c);
	for (i = 0; i < c; i++) {
		itemArray[i] = p.item(i);
	}
	for (i = 0; i < itemArray.length; i++) {
		switch (itemArray[i].name()) {
			case "NMR Spectrum":
				var nmrSpc = new NMRSpectrum(itemArray[i]);
				print("Spectrum");
				print(nmrSpc.title);
				var tit = draw.text("<h2>" + nmrSpc.title + "</h2>", true);
				tit.top = nmrSpc.top;
				tit.left = nmrSpc.left + (nmrSpc.width - tit.width) / 2
				nmrSpc.top = tit.bottom;
				nmrSpc.height = nmrSpc.height - tit.height;
				break;
			case "Molecule":
				print("Molecule");
				print(itemArray[i]);
				break;
			default:
				print(itemArray[i]);
				break;
		}
	}
	w.update();
}

/* loadUi.qs */
function loadUi() {
	//Simple button
	var buttonText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ui version=\"4.0\"><widget class=\"QPushButton\" name=\"button\"></widget></ui>"
	var button = Application.loadUi(buttonText);
	print(button);
	//Dialog
	var diagText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ui version=\"4.0\"><class>CustomDialog</class><widget class=\"QDialog\" name=\"CustomDialog\">  <property name=\"geometry\">   <rect>    <x>0</x>    <y>0</y>    <width>250</width>   <height>75</height>   </rect>  </property>  <property name=\"windowTitle\">   <string>Custom Dialog</string>  </property> <layout class=\"QGridLayout\" name=\"gridLayout\"><item row=\"0\" column=\"0\">    <widget class=\"QLabel\" name=\"label\"><property name=\"text\">      <string>Text:</string>     </property> </widget></item><item row=\"0\" column=\"1\"> <widget class=\"QLineEdit\" name=\"lineEdit\"/>   </item><item row=\"1\" column=\"0\" colspan=\"2\">    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">     <item>      <spacer name=\"horizontalSpacer\">       <property name=\"orientation\">        <enum>Qt::Horizontal</enum>       </property>       <property name=\"sizeHint\" stdset=\"0\">        <size>         <width>40</width>         <height>20</height>        </size>       </property>      </spacer>     </item> <item>      <widget class=\"QPushButton\" name=\"okPushButton\">       <property name=\"text\">        <string>&amp;Ok</string>       </property>      </widget>     </item><item>      <widget class=\"QPushButton\" name=\"cancelPushButton\">       <property name=\"text\">        <string>&amp;Cancel</string>       </property>      </widget>     </item>    </layout></item></layout></widget><connections>  <connection>   <sender>okPushButton</sender>   <signal>clicked()</signal>   <receiver>CustomDialog</receiver>   <slot>accept()</slot>   <hints>    <hint type=\"sourcelabel\">     <x>117</x>     <y>51</y>    </hint>    <hint type=\"destinationlabel\">     <x>124</x>     <y>37</y>    </hint>   </hints>  </connection>  <connection>   <sender>cancelPushButton</sender>   <signal>clicked()</signal>   <receiver>CustomDialog</receiver>   <slot>reject()</slot>   <hints>    <hint type=\"sourcelabel\">     <x>202</x>     <y>51</y>    </hint>    <hint type=\"destinationlabel\">     <x>124</x>     <y>37</y>    </hint>   </hints>  </connection> </connections></ui>";
	var diag = Application.loadUi(diagText);
	print(diag);
	diag.exec();
	//Using Qt Designer file
	//var otherDiag = Application.loadUiFile("path_to_file.qs");
	//otherDiag.exec()
}

/******************************************************************************************************
magnitude_each_1H_spectrum.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
// This example function demonstrates how to access data points of 1D spectrum, modify them and show the result.
// It applies magnitude to all opened 1H 1D spectra. Note that this is just a demonstrative example but not the right way to magnitude the spectra.
function magnitude_each_1H_spectrum() {
	var re = new Number;
	var im = new Number;
	var dw = new DocumentWindow(Application.mainWindow.activeWindow());
	var pageCount = dw.pageCount();
	for (var i = 0; i < pageCount; i++) {
		var page = new Page(dw.page(i));
		var itemCount = page.itemCount();
		for (var j = 0; j < itemCount; j++) {
			var spec = new NMRSpectrum(page.item(j));
			if (spec.isValid()) // if page item is a spectrum
			{
				print("Page #" + i + " Item #" + j + " is " + spec.dimCount + "D spectrum (uuid " + spec.uuid + ")");
				if (spec.dimCount == 1) {
					if (spec.nucleus() == "1H") {
						nmr.beginModification(spec);
						var ptsCount = spec.count();
						for (var k = 0; k < ptsCount; k++) {
							if (k % 1024 == 0) {
								page.update();
								dw.update();
							}
							re = spec.real(k);
							re *= re;
							im = spec.imag(k);
							im *= im;
							spec.setReal(k, Math.sqrt(re + im));
						}
						nmr.endModification(spec);
					}
				}
			}
			else {
				print("Item #" + j + " is not a spectrum.")
			}
		}
		page.update();
	}
}

/*******************************************************************************************
messageBoxTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

function criticalTest() {
	MessageBox.critical("This is critical error.");
}

function questionTest() {
	MessageBox.question("How are you?");
	MessageBox.question("Do you want to continue?", MessageBox.Yes, MessageBox.No, MessageBox.Cancel);
	if (MessageBox.question("Are you sure?", MessageBox.Yes, MessageBox.No, MessageBox.Cancel, "Last Question") == MessageBox.Cancel)
		print("Canceled");
}

function informationTest() {
	MessageBox.information("Everything is fine.");
}

function warningTest() {
	MessageBox.warning("Insignificant problems detected.");
}

function messageBoxText() {
	criticalTest();
	questionTest();
	informationTest();
	warningTest();
}

/******************************************************************************************************
moleculeTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function moleculeTest() {
	var moleculePlugin = new MoleculePlugin(molecule);
	print(moleculePlugin);
	var mol = new Molecule(moleculePlugin.activeMolecule());
	print(mol);
	print(mol.getMolfile());
	var atomList = mol.atoms();
	print("Atom Count: ", mol.atomCount);
	print("Bond Count: ", mol.bondCount);
	print("Atom List: ", atomList);
	print("Atom List Length: ", atomList.length);
	var myAtom = new Atom(atomList[2]);
	print("Element: ", myAtom.elementSymbol);
	print("Proton Notation: ", myAtom.protonNotation);
	print("Alias: ", myAtom.alias);
	print("Text: ", myAtom.text);
	print("Charge: ", myAtom.charge);
	print("nH: ", myAtom.nH);
	print("All nH: ", myAtom.nHAll);
	print("Isotope: ", myAtom.isotope);
	print("Valence: ", myAtom.valence);
	print("Color: ", myAtom.color);
	var bondList = mol.bonds();
	print("Bond List: ", bondList);
	print("Bond List Length: ", bondList.length);
	var myBond = new Bond(bondList[1]);
	print("atom1: ", myBond.atom1);
	print("atom2: ", myBond.atom2);
	print("Bond Type:", myBond.bondType);
	print("Bond Stereo: ", myBond.bondStereo);
	print("Numeric value of btDouble: ", Bond.btDouble);
	mol.detectAromaticAtoms();
	print("Is atom number 1 aromatic: ", mol.isAromaticAtom(1));
	print("Aromatic atoms list: ", mol.aromaticAtoms());
	print("List of atoms symmetrical with atom number 1: ", mol.symmetricalAtoms(1));
	print("SMILES: ", mol.generateSMILES());
	print("InChI: ", mol.generateInChi());
}

/** Get/Set molecule graphic settings
*/
function moleculeGraphicPropertiesTest() {
	var moleculePlugin = new MoleculePlugin(molecule);
	print(moleculePlugin);
	var mol = new Molecule(moleculePlugin.activeMolecule());
	//get the properties object
	var graphProp = mol.graphicProperties();
	//calling print will show the available properties
	print(graphProp);
	//some examples
	graphProp.showAllC = false;
	graphProp.numberFontColor = "blue"
	graphProp.showTermC = false;
	graphProp.showLabel = true
	graphProp.showOthers = false
	//check our changes
	print(graphProp);
	//set the properties and update
	mol.setGraphicProperties(graphProp);
	mol.update();
	mainWindow.activeWindow().update();
}

/** Changes the proton notation of all the atoms in the active molecule
*/
function protonNotation() {
	var moleculePlugin = new MoleculePlugin(molecule)
	var mol = new Molecule(moleculePlugin.activeMolecule())
	var nAtom = mol.atomCount
	for (var i = 0; i < nAtom; ++i) {
		//valid values Atom.AB, Atom.ALPHABETA, Atom.AXEQ, Atom.CISTRANS, Atom.QUOTES
		mol.atom(i).protonNotation = Atom.AXEQ
	}
	mol.update()
	mainWindow.activeWindow().update()
}

function labileProton() {
	var moleculePlugin = new MoleculePlugin(molecule)
	var mol = new Molecule(moleculePlugin.activeMolecule())
	var nAtom = mol.atomCount
	for (var i = 1; i <= nAtom; ++i) {
		print("{0} is labile {1}".format(i, mol.isLabileProton(i)));
	}
}

/******************************************************************************************************
multipletTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals NMRSpectrum, print, SpectrumRegion, Multiplets, Multiplet, MessageBox, nmr*/
/*jslint plusplus: true, indent: 4*/

function multipletTest() {
	'use strict';
	var spec, sMult, mult, myMultiplets;
	spec = new NMRSpectrum(nmr.activeSpectrum());
	if (spec.isValid()) {
		//print(spec.multiplets());
		myMultiplets = new Multiplets();
		sMult = new Multiplets(spec.multiplets());
		mult = new Multiplet(spec, SpectrumRegion(5.55, 6.0));
		mult.color = "darkblue";
		myMultiplets.append(mult);
		mult = new Multiplet(spec, SpectrumRegion(8.0, 8.25));
		myMultiplets.append(mult);
		myMultiplets.normalizeWithNuclideCount(spec);
		print(myMultiplets);
		spec.setMultiplets(myMultiplets);
		//print(spec.multiplets());
		spec.process();
	} else {
		MessageBox.critical("Invalid Spectrum");
	}
}

/*******************************************************************************************
networkTest.qs
Copyright (C) 2015 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

/*globals NetworkAccessManager, NetworkRequest, print*/

function networkTest() {
	"use strict";

	var reply,
		netMan = new NetworkAccessManager(),
		xml = '<?xml version="1.0" encoding="utf-8"?>' +
			'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">' +
			'<soap:Body>' +
			'<ns1:GetWeatherInformation xmlns:ns1="http://ws.cdyne.com/WeatherWS/" />' +
			'</soap:Body>' +
			'</soap:Envelope>',
		netReq = new NetworkRequest("http://wsf.cdyne.com/WeatherWS/Weather.asmx");
	netReq.setHeader(NetworkRequest.ContentTypeHeader, "text/xml;charset=utf-8");

	reply = netMan.post(netReq, xml);
	reply.finished.connect(reply, function () {
		print(this.readAll());
		this.markForDeletion();//this has to be called when the reply has been processed
	});
}

/******************************************************************************************************
nmrArithmeticTest.qs
Copyright (C) 2011 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
function nmrAddTest() {
	var dw = mainWindow.activeDocument
	var numberOfNMR = dw.itemCount("NMR Spectrum")
	if (numberOfNMR > 1) {
		var firstNMR = new NMRSpectrum(dw.item(0, "NMR Spectrum"))
		var secondNMR = new NMRSpectrum(dw.item(1, "NMR Spectrum"))
		if (firstNMR != undefined && secondNMR != undefined && firstNMR.isValid() && secondNMR.isValid()) {
			var newPage = dw.newPage()
			var resultNMR = new NMRSpectrum(newPage.cloneItems(firstNMR))
			var nmrArith = new NMRArithmetic
			if (nmrArith.add(firstNMR, secondNMR, resultNMR) == false) {
				MessageBox.critical(nmrArith.lastError, MessageBox.Ok)
				return false
			}
			resultNMR.fitToHeight()
			dw.setCurPage(newPage)
			newPage.update()
		}
	}
}

function nmrAddArrayedTest() {
	var dw = mainWindow.activeDocument
	var numberOfNMR = dw.itemCount("NMR Spectrum")
	var stackedNMR = undefined
	var spcCount
	for (var i = 0; i < numberOfNMR; ++i) {
		var nmrSpc = new NMRSpectrum(dw.item(i, "NMR Spectrum"))
		if (nmrSpc.specCount > 1) {
			spcCount = nmrSpc.specCount
			stackedNMR = nmrSpc
			break
		}
	}
	if (stackedNMR == undefined) {
		MessageBox.critical("No Stacked Spectra", MessageBox.Ok)
		return false
	}

	var resultNMR = nmr.extractSpectrumFromArrayedItem(stackedNMR)
	if (resultNMR.isValid()) {
		var nmrArith = new NMRArithmetic
		if (nmrArith.add(stackedNMR, 0, stackedNMR, 1, resultNMR) == false) {
			MessageBox.critical(nmrArith.lastError, MessageBox.Ok)
			return false
		}
		resultNMR.fitToHeight()
	}
}

function nmrMulTest() {
	var dw = mainWindow.activeDocument
	var numberOfNMR = dw.itemCount("NMR Spectrum")
	if (numberOfNMR > 1) {
		var firstNMR = new NMRSpectrum(dw.item(0, "NMR Spectrum"))
		var secondNMR = new NMRSpectrum(dw.item(1, "NMR Spectrum"))
		if (firstNMR != undefined && secondNMR != undefined && firstNMR.isValid() && secondNMR.isValid()) {
			var newPage = dw.newPage()
			var resultNMR = new NMRSpectrum(newPage.cloneItems(firstNMR))
			var nmrArith = new NMRArithmetic
			if (nmrArith.mul(firstNMR, secondNMR, resultNMR) == false) {
				MessageBox.critical(nmrArith.lastError, MessageBox.Ok)
				return false
			}
			resultNMR.fitToHeight()
			dw.setCurPage(newPage)
			newPage.update()
		}
	}
}

function nmrScaleTest() {
	var dw = mainWindow.activeDocument
	var numberOfNMR = dw.itemCount("NMR Spectrum")
	if (numberOfNMR) {
		var nmrSpc = new NMRSpectrum(dw.item(0, "NMR Spectrum"))
		if (nmrSpc != undefined && nmrSpc.isValid()) {
			var newPage = dw.newPage()
			var resultNMR = new NMRSpectrum(newPage.cloneItems(nmrSpc))
			var nmrArith = new NMRArithmetic
			if (nmrArith.scale(0.5, nmrSpc, resultNMR) == false) {
				MessageBox.critical(nmrArith.lastError, MessageBox.Ok)
				return false
			}
			resultNMR.fitToHeight()
			dw.setCurPage(newPage)
			newPage.update()
		}
	}
}

function nmrScaleArrayedTest() {
	var dw = mainWindow.activeDocument
	var numberOfNMR = dw.itemCount("NMR Spectrum")
	var stackedNMR = undefined
	var spcCount
	for (var i = 0; i < numberOfNMR; ++i) {
		var nmrSpc = new NMRSpectrum(dw.item(i, "NMR Spectrum"))
		if (nmrSpc.specCount > 1) {
			spcCount = nmrSpc.specCount
			stackedNMR = nmrSpc
			break
		}
	}
	if (stackedNMR == undefined) {
		MessageBox.critical("No Stacked Spectra", MessageBox.Ok)
		return false
	}

	var resultNMR = nmr.extractSpectrumFromArrayedItem(stackedNMR)
	if (resultNMR.isValid()) {
		var nmrArith = new NMRArithmetic
		if (nmrArith.scale(0.5, stackedNMR, 0, resultNMR) == false) {
			MessageBox.critical(nmrArith.lastError, MessageBox.Ok)
			return false
		}
		resultNMR.fitToHeight()
	}
}

/******************************************************************************************************
nmrProcessingTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function nmrProcessingTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	var p = new NMRProcessing(spec.proc);
	print(p.getParameter("DC"));
	print(p.getParameter("FT"));
	print(p.getParameter("FT[1].Quadrature"));
	print(p.getParameter("zf"));
	print(p.getParameter("LP"));
	print(p.getParameter("LP.Method"));
	print(p.getParameter("BC"));
	print(p.getParameter("BC.apply"));
	print(p.getParameter("BC.algorithm"));
	print(p.getParameter("BC.filter"));
	print(p.getParameter("ds"));
	print(p.getParameter("ds.method"));
	print(p.getParameter("ss"));
	print(p.getParameter("ss.signals"));
	print(p.getParameter("smooth"));
	print(p.getParameter("smooth.method"));
	print(p.getParameter("smooth.average.span"));
	print(p.getParameter("pp"));
	print(p.getParameter("pp.apply"));
	print(p.getParameter("pp.peaktype"));
	print(p.getParameter("binning"));
	print(p.getParameter("binning.width"));
	print(p.getParameter("ref"));
	print(p.getParameter("ref.autotune"));
	print(p.getParameter("rev[1]"));
	print(p.getParameter("norm"));
	print(p.getParameter("norm.range"));
	print(p.getParameter("trunc"));
	print(p.getParameter("trunc.after"));
	print(p.getParameter("comp"));
	print(p.getParameter("comp.ratio"));
	print(p.getParameter("mult"));
	spec.proc = p;
	spec.process();
	//var result = spec.process();
	//MessageBox.information("Process "+result); 
	mainWindow.activeWindow().update();
}

function integralsTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	var p = new NMRProcessing(spec.proc);
	//1D Automatic integration parameters
	//p.setParameter("integration.method", "Auto");
	//Derivative Method
	//p.setParameter("integration.auto.algorithm", "Derivative");
	//p.setParameter("integration.auto.sensitivity", 7);
	//p.setParameter("integration.auto.autosensitivity", true);
	//PeakPicking Method
	//p.setParameter("integration.auto.algorithm", "PeakPicking");
	//p.setParameter("integration.auto.jmax", 25);
	//p.setParameter("integration.auto.peakfactor", 6);

	//integral list import 
	//var regs = SpectrumRegion.importList("/home/isaac/tmp/mnova/myintegrals.txt");
	var regs = new Array(2);
	regs[0] = new SpectrumRegion(2.0, 2.5);
	regs[1] = new SpectrumRegion(7.0, 7.5);
	p.setParameter("integration.method", "Predefined");
	p.setParameter("integration.regions", regs);
	p.setParameter("integration.apply", true);
	//integral list export:
	//SpectrumRegion.exportList(regs, "/home/isaac/tmp/mnova/exported_integrals.txt"); 
	spec.proc = p;
	spec.process();
	mainWindow.activeWindow().update();
}

function cutsTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	var p = new NMRProcessing(spec.proc);
	var regs = spec.autoDetectNoiseRegions(); //this returns a list of SpectrumRegion object
	regs.push(new SpectrumRegion(0.5, -0.5)); //We can add/remove regions from the list
	//regs.push(new SpectrumRegion(0.75, 0.9));
	print(regs);
	p.setParameter("cuts.apply", true);
	p.setParameter("cuts.list", regs); //now we apply the cuts list to the process object
	spec.proc = p;
	spec.process();
	//var result = spec.process();
	//MessageBox.information("Process "+result); 
	mainWindow.activeWindow().update();
}

function apodizationTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	var p = new NMRProcessing(spec.proc);
	//Along dim 1
	print(p.getParameter("Apodization[1]"));
	p.setParameter("Apodization[1].Exp.apply", true);
	p.setParameter("Apodization[1].Exp.value", 0.5);
	p.setParameter("Apodization[1].fp.apply", true);
	p.setParameter("Apodization[1].fp.value", 0.5);
	print(p.getParameter("Apodization[1]"));
	spec.proc = p;
	spec.process();
	mainWindow.activeWindow().update();
}

function phaseCorrectionTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	var p = new NMRProcessing(spec.proc);
	print("Old Method: ", p.getParameter("PC.algorithms"));
	p.setParameter("PC.method", "Global, Metabonomics");
	print("New Method: ", p.getParameter("PC.algorithms"));
	//      p.setParameter("PC.method", "Manual");
	//      p.setParameter("PC.PH0", 0);
	//      p.setParameter("PC.PH1", Math.PI / 2);
	print("Init: {0}".format(p.getParameter("PC.InitMode")));
	p.setParameter("PC.InitMode", "InitZero");
	print("New Init: {0}".format(p.getParameter("PC.InitMode")));
	spec.proc = p;
	spec.process();
	mainWindow.activeWindow().update();
}

function referenceTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	spec.reference(1, 6.0, 3.0, true, 0.1, "Script Annotation"); //auto tune tries to find the maximum around 5.9 with a tolerance of 0.1	
	spec.update();
	mainWindow.activeWindow().update();

	/*	
		var spec = new NMRSpectrum( nmr.activeSpectrum() );
		var p = new NMRProcessing(spec.proc);	
	
		p.setParameter("ref[1].apply", true);
		p.setParameter("ref[1].shift", 4.45, 4.40);
		p.setParameter("ref[1].annotation", "Script Annotation");
		spec.proc = p;
		spec.process();	
		mainWindow.activeWindow().update();
	*/
}

function multipointBaselineCorrectionTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	var p = new NMRProcessing(spec.proc);
	//original params
	print(p.getParameter("BC[1].BCMultipoint"));
	//set new params
	p.setParameter("BC[1].BCMultipoint.Apply", true);
	p.setParameter("BC[1].BCMultipoint.smooth", 5);
	p.setParameter("BC[1].BCMultipoint.Algorithm.type", "Segments");
	p.setParameter("BC[1].bcmultipoint.algorithm.lambda", 20);
	//set point params. An array of objects with x and y properties is needed. If the y property is not set
	//the value of the spectrum height will be use by default otherwise the point will be marked as "free"
	var newPoints = []
	var point = { x: 1.0 } //x coordinates in PPM. y propery not set, the spectrum height in that point will be used
	newPoints.push(point);
	var anotherPoint = { x: 8.0, y: 5 }
	newPoints.push(anotherPoint);
	p.setParameter("bc[1].bcmultipoint.points", newPoints);
	//check the modified values
	print(p.getParameter("BC[1].BCMultipoint"));
	//process spectrum
	spec.process(p);
	//update
	spec.update();
	mainWindow.activeWindow().update();
}

function normalizeTest() {
	var spec, p;
	spec = new NMRSpectrum(nmr.activeSpectrum());
	p = new NMRProcessing(spec.proc);
	print(p.getParameter("norm"));
	print(p.getParameter("norm.range"));
	p.setParameter("norm.method", "LargestPeakRange");
	p.setParameter("norm.range", [5.0, 5.5]);
	p.setParameter("norm.apply", true);
	p.setParameter("norm.value", 1);
	print(p.getParameter("norm"));
	print(p.getParameter("norm.range"));
	spec.process(p);
	spec.update();
	mainWindow.activeWindow().update();
}

function freqShiftTest() {
	'use strict'

	var spec = new NMRSpectrum(nmr.activeSpectrum()),
		p = new NMRProcessing(spec.proc),
		freqShift = p.getParameter("FreqShift");

	print(freqShift);
}

function printParameter(aParam) {
	'use strict'

	var spec = new NMRSpectrum(nmr.activeSpectrum()),
		p = new NMRProcessing(spec.proc),
		paramValue = p.getParameter(aParam);

	print(aParam + ": " + JSON.stringify(paramValue, null, " "));
}

function setParameter(aParam, aValue) {
	'use strict'

	var spec = new NMRSpectrum(nmr.activeSpectrum()),
		p = new NMRProcessing(spec.proc),
		paramValue = p.getParameter(aParam);

	print(aParam + ": " + JSON.stringify(paramValue, null, " "));
	p.setParameter(aParam, aValue);
	paramValue = p.getParameter(aParam);
	print(aParam + ": " + JSON.stringify(paramValue, null, " "));
}

/******************************************************************************************************
nmrPropertiesTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function printProp(aSpec, aPropName) {
	print(aPropName, ": ", aSpec.getProperty(aPropName));
}

function properties() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());

	printProp(spec, "background.color");
	printProp(spec, "background.opacity");
	printProp(spec, "curve.linestyle");
	printProp(spec, "curve.linewidth");
	printProp(spec, "curve.color");
	printProp(spec, "legend.show");
	printProp(spec, "legend.width.mm");
	printProp(spec, "legend.width.inches");
	printProp(spec, "legend.textwidth.cm");
	printProp(spec, "contours.positivenumber");
	printProp(spec, "contours.negativenumber");
	printProp(spec, "contours.scaling");
	printProp(spec, "palette");
	printProp(spec, "grid.showhorizontal");
	printProp(spec, "grid.showvertical");
	printProp(spec, "grid.showover");
	printProp(spec, "grid.showframe");
	printProp(spec, "grid.showtracesframe");
	printProp(spec, "grid.color");
	printProp(spec, "axes.color");
	printProp(spec, "axes.font");
	printProp(spec, "axes.margin.mm");
	printProp(spec, "axes.horizontal.showlabel");
	printProp(spec, "axes.vertical.showlabel");
	printProp(spec, "axes.horizontal.maxdigits");
	printProp(spec, "axes.vertical.maxdigits");
	printProp(spec, "axes.horizontal.label");
	printProp(spec, "axes.horizontal.visible");
	printProp(spec, "axes.vertical.label");
	printProp(spec, "axes.vertical.visible");
	printProp(spec, "axes.horizontal.units");
	printProp(spec, "axes.vertical.units");
	printProp(spec, "peaks.show");
	printProp(spec, "peaks.color");
	printProp(spec, "peaks.font");
	printProp(spec, "peaks.showtick");
	printProp(spec, "peaks.pointer");
	printProp(spec, "peaks.units");
	printProp(spec, "peaks.decimals");
	printProp(spec, "integrals.show");
	printProp(spec, "integrals.label.show");
	printProp(spec, "integrals.label.color");
	printProp(spec, "integrals.label.font");
	printProp(spec, "integrals.label.decimals");
	printProp(spec, "integrals.label.position");
	printProp(spec, "integrals.label.margin");
	printProp(spec, "integrals.curve.show");
	printProp(spec, "integrals.curve.color");
	printProp(spec, "integrals.curve.margin");
	printProp(spec, "integrals.curve.maxheight");
	printProp(spec, "integrals.curve.shape");
	printProp(spec, "multiplets.show");
	printProp(spec, "multiplets.font");
	printProp(spec, "multiplets.fontcolor");
	printProp(spec, "multiplets.decimals");
	printProp(spec, "multiplets.margin");
	printProp(spec, "multiplets.labelcolor");
	printProp(spec, "title.visible");

	//spec.setProperty("axes.margin.mm", 3);
	//spec.setProperty("axes.vertical.visible", false);
	//spec.setProperty("curve.color", "darkgreen");

	//spec.update();

	//mainWindow.activeWindow().update();
}

function _multipletProperties() {
	var spec = new NMRSpectrum(nmr.activeSpectrum())
	printProp(spec, "multiplets.integral.curve.show")
	printProp(spec, "multiplets.integral.label.font")
	printProp(spec, "multiplets.integral.label.show")

	spec.setProperty("multiplets.integral.curve.show", false)
	spec.update()
	mainWindow.activeWindow().update()
}

function peaksFontProperties() {
	var spec = new NMRSpectrum(nmr.activeSpectrum()),
		_f = spec.getProperty("peaks.font");
	print("peaks.font: %1".arg(JSON.stringify(_f)));
	_f.size = _f.size + 10
	print("new peaks.font: %1".arg(JSON.stringify(_f)));
	spec.setProperty("peaks.font", _f)
	spec.update()
	mainWindow.activeWindow().update()
}

/******************************************************************************************************
nmrSelectionTest.qs
Copyright (C) 2011 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function nmrSelectionTest() {
	var dw = mainWindow.activeWindow();
	var cP = dw.curPage();
	var nmrCount = cP.itemCount("NMR Spectrum");
	if (nmrCount == 0) {
		print("There is no NMR Spectrum");
		return;
	}
	var itemList = new Array(nmrCount);
	for (var i = 0; i < nmrCount; i++)
		itemList[i] = cP.item(i, "NMR Spectrum");
	dw.setSelection(itemList);
	dw.setActive(itemList[0]);
	var sel = dw.selection();
	print("Items selected: " + sel.length);
	for (var i = 0; i < sel.length; i++)
		print(sel[i]);
	dw.update();
}

/******************************************************************************************************
OLEContainerTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function OLEContainerTest() {
	print(OLEContainer);
	print("" + OLEContainer);

	var fileName = FileDialog.getOpenFileName("Zip file (*.zip);;All files (*.*)", "Select File", Dir.home());
	if (!fileName.length)
		return;
	print(fileName);
	var item = OLEContainer.createObjectFromFile(fileName);

	print(item);
	print("" + item);
}
/******************************************************************************************************
openSpecWithMols.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

// Opens a spectrum at aSpecPath and all the molfiles located in the same directory
function openSpecWithMols(aSpecPath) {
	var dirPath = File.absDirPath(aSpecPath);
	var dir = Dir(dirPath);
	dir.cdUp();
	var files = getMaskFiles(dirPath, dir.absPath, "*.mol", "*", false);
	files.push(dirPath);
	serialization.open(files);
}

/******************************************************************************************************
peakTest2D.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function peakTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	var sR = new SpectrumRegion(4.0, 3.5, 75, 65);
	var ps = new Peaks(spec, sR);//peaks in sR
	//ps.at(0).type=Peak.Artifact;
	//ps.at(0).type=Peak.Minimum
	print(ps);
	var p = new Peak(72.73, 3.17, spec);//single peak
	print(p);
	ps.append(p);
	spec.setPeaks(ps);
	print(spec.peaks());
	spec.process();
}
/******************************************************************************************************
peakTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function peakTest() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	var sR = new SpectrumRegion(7.0, 7.5);
	var ps = new Peaks(spec, sR); //fill the list with the peaks in sR
	print(ps);
	var p = new Peak(1.26, spec);
	p.annotation = "Disolvent";
	print(p);
	ps.append(p);
	//var myPeak = new Peak( 8,08, 122.1 );
	//ps.append(myPeak);
	spec.setPeaks(ps);//Set the peaks to ps
	print(spec.peaks());
	spec.update();
	mainWindow.activeWindow().update();
}

/******************************************************************************************************
pixmapTest.qs
Copyright (C) 2016 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function pixmapTest() {
	var dw,
		cP,
		ui = Application.loadUi('<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"><class>Dialog</class><widget class="QDialog" name="Dialog"><property name="geometry"><rect><x>0</x><y>0</y><width>643</width><height>606</height></rect></property><property name="windowTitle"><string>Dialog</string></property><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QScrollArea" name="scrollArea"><property name="widgetResizable"><bool>true</bool></property><widget class="QWidget" name="scrollAreaWidgetContents"><property name="geometry"><rect><x>0</x><y>0</y><width>621</width><height>447</height></rect></property><layout class="QHBoxLayout" name="horizontalLayout_2"><item><widget class="QLabel" name="label"><property name="text"><string>Image</string></property></widget></item></layout></widget></widget></item><item><layout class="QGridLayout" name="gridLayout"><item row="0" column="0"><widget class="QLabel" name="label_2"><property name="sizePolicy"><sizepolicy hsizetype="Preferred" vsizetype="Fixed"><horstretch>0</horstretch><verstretch>0</verstretch></sizepolicy></property><property name="text"><string>Resolution:</string></property></widget></item><item row="0" column="1"><widget class="QSpinBox" name="spinBox"><property name="keyboardTracking"><bool>false</bool></property><property name="suffix"><string> dpi</string></property><property name="maximum"><number>1000</number></property><property name="singleStep"><number>10</number></property></widget></item><item row="1" column="0"><widget class="QLabel" name="label_3"><property name="text"><string>Angle:</string></property></widget></item><item row="1" column="1"><widget class="QSpinBox" name="angleSpinBox"><property name="keyboardTracking"><bool>false</bool></property><property name="suffix"><string> </string></property><property name="maximum"><number>360</number></property><property name="singleStep"><number>10</number></property></widget></item></layout></item><item><widget class="QPushButton" name="pushButton"><property name="text"><string>Reload</string></property></widget></item><item><widget class="QDialogButtonBox" name="buttonBox"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="standardButtons"><set>QDialogButtonBox::Close</set></property></widget></item></layout></widget><resources/><connections><connection><sender>buttonBox</sender><signal>accepted()</signal><receiver>Dialog</receiver><slot>accept()</slot><hints><hint type="sourcelabel"><x>248</x><y>254</y></hint><hint type="destinationlabel"><x>157</x><y>274</y></hint></hints></connection><connection><sender>buttonBox</sender><signal>rejected()</signal><receiver>Dialog</receiver><slot>reject()</slot><hints><hint type="sourcelabel"><x>316</x><y>260</y></hint><hint type="destinationlabel"><x>286</x><y>274</y></hint></hints></connection></connections></ui>'),
		sel,
		angle = 0,
		index = 0,
		onReload = function () {
			dw = new DocumentWindow(mainWindow.activeWindow()),
				cP = new Page(dw.curPage()),
				pages = dw.pages(),
		if (index >= pages.length)
				index = 0;
			sel = dw.selection();
			print("Items selected: %1. Resolution: %2".arg(sel.length).arg(ui.widgets.spinBox.value));
			if (sel.length) {
				ui.widgets.label.pixmap = draw.toPixmap(sel, ui.widgets.spinBox.value).rotated(angle);
				//ui.widgets.label.pixmap = itm.toPixmap(ui.widgets.spinBox.value).rotated(angle);
				gc();
			} else {
				ui.widgets.label.pixmap = draw.toPixmap(pages[index++], ui.widgets.spinBox.value).rotated(angle);
				gc();
			}
		},
		onAngleChanged = function (aValue) {
			angle = aValue;
			onReload();
		},
		onFinished = function () {
			ui.deleteLater();
			gc();
		},
		onDestroyed = function () {
			print("Destroyed");
			gc();
		};
	ui.widgets.spinBox.value = 300;
	ui.widgets.pushButton.clicked.connect(onReload);
	ui.widgets.angleSpinBox["valueChanged(int)"].connect(onAngleChanged);
	ui.widgets.spinBox["valueChanged(int)"].connect(onReload);
	ui.finished.connect(onFinished);
	ui.destroyed.connect(onDestroyed);
	onReload();
	ui.show();
}

/******************************************************************************************************
predictAndCompare.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function predictAndCompare() {
	var dw = new DocumentWindow(mainWindow.activeWindow());
	var cP = new Page(dw.curPage());
	var nmrCount = cP.itemCount("NMR Spectrum");
	var molCount = cP.itemCount("Molecule");
	var itemList = new Array(2);
	if (nmrCount == 0 || molCount == 0) {
		var errString;
		if (nmrCount == 0)
			errString = "No NMR Spectrum";
		else
			errString = "No Molecule";
		MessageBox.critical(errString, MessageBox.Ok);
		return -1;
	}
	itemList[0] = cP.item(0, "NMR Spectrum");
	itemList[1] = cP.item(0, "Molecule");

	dw.setSelection(itemList);
	mainWindow.doAction("nmrCompare");
}

/******************************************************************************************************
predictedMoleculeTest.qs
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function predictedMoleculeTest() {
	'use strict';
	var mol = new Molecule(Application.molecule.activeMolecule()),
		predictionResult;

	if (Application.NMRPredictor === undefined)
		throw "Predictor Plugin not loaded";

	if (!mol.isValid())
		throw "Invalid Molecule";

	predictionResult = mol.nmrPrediction("1H", true);
	print(JSON.stringify(predictionResult));
}

function setMoleculePrediction() {
	'use strict';
	var predStr = '',
		predObj = JSON.parse('[{"atom":{"index":1,"h":"a"},"shift":{"value":1.9000000953674316,"error":5}},{"atom":{"index":2,"h":"a"},"shift":{"value":5.4800004959106445,"error":0.2},"js":[{"atom":{"index":16},"j":{"value":9.300000190734863,"error":-1}}]},{"atom":{"index":6,"h":"a"},"shift":{"value":1.0000001192092896,"error":0.35},"js":[{"atom":{"index":10,"h":"a"},"j":{"value":1.5,"error":-1}},{"atom":{"index":11,"h":"a"},"j":{"value":0.5,"error":0.5}},{"atom":{"index":15,"h":"a"},"j":{"value":0.5,"error":0.5}}]},{"atom":{"index":9,"h":"a"},"shift":{"value":3.81000018119812,"error":0.2},"js":[{"atom":{"index":9,"h":"b"},"j":{"value":-11.5,"error":-1}},{"atom":{"index":9,"h":"c"},"j":{"value":-11.5,"error":-1}}]},{"atom":{"index":9,"h":"b"},"shift":{"value":3.81000018119812,"error":0.2},"js":[{"atom":{"index":9,"h":"a"},"j":{"value":-11.5,"error":-1}},{"atom":{"index":9,"h":"c"},"j":{"value":-11.5,"error":-1}}]},{"atom":{"index":9,"h":"c"},"shift":{"value":3.81000018119812,"error":0.2},"js":[{"atom":{"index":9,"h":"a"},"j":{"value":-11.5,"error":-1}},{"atom":{"index":9,"h":"b"},"j":{"value":-11.5,"error":-1}}]},{"atom":{"index":10,"h":"a"},"shift":{"value":7.3000006675720215,"error":0.35},"js":[{"atom":{"index":6,"h":"a"},"j":{"value":1.5,"error":-1}},{"atom":{"index":11,"h":"a"},"j":{"value":7.5,"error":-1}}]},{"atom":{"index":11,"h":"a"},"shift":{"value":7.950000286102295,"error":0.35},"js":[{"atom":{"index":10,"h":"a"},"j":{"value":7.5,"error":-1}},{"atom":{"index":6,"h":"a"},"j":{"value":0.5,"error":0.5}}]},{"atom":{"index":14,"h":"a"},"shift":{"value":8.620000839233398,"error":0.2},"js":[{"atom":{"index":15,"h":"a"},"j":{"value":7.5,"error":-1}}]},{"atom":{"index":15,"h":"a"},"shift":{"value":7.210000514984131,"error":0.35},"js":[{"atom":{"index":14,"h":"a"},"j":{"value":7.5,"error":-1}},{"atom":{"index":6,"h":"a"},"j":{"value":0.5,"error":0.5}}]},{"atom":{"index":16},"shift":{"value":3.120000123977661,"error":0.2},"js":[{"atom":{"index":2,"h":"a"},"j":{"value":9.300000190734863,"error":-1}},{"atom":{"index":21,"h":"a"},"j":{"value":8.100000381469727,"error":-1}},{"atom":{"index":21,"h":"b"},"j":{"value":8.100000381469727,"error":-1}}]},{"atom":{"index":18,"h":"a"},"shift":{"value":2.630000352859497,"error":0.2},"js":[{"atom":{"index":18,"h":"b"},"j":{"value":-12.5,"error":-1}},{"atom":{"index":19,"h":"a"},"j":{"value":7.900000095367432,"error":-1}}]},{"atom":{"index":18,"h":"b"},"shift":{"value":3.0500001907348633,"error":0.2},"js":[{"atom":{"index":18,"h":"a"},"j":{"value":-12.5,"error":-1}},{"atom":{"index":19,"h":"a"},"j":{"value":7.900000095367432,"error":-1}}]},{"atom":{"index":19,"h":"a"},"shift":{"value":2.2400002479553223,"error":0.35},"js":[{"atom":{"index":18,"h":"a"},"j":{"value":7.900000095367432,"error":-1}},{"atom":{"index":18,"h":"b"},"j":{"value":7.900000095367432,"error":-1}},{"atom":{"index":20,"h":"a"},"j":{"value":1.7999999523162842,"error":-1}},{"atom":{"index":24,"h":"a"},"j":{"value":6.199999809265137,"error":-1}},{"atom":{"index":25,"h":"a"},"j":{"value":0.4000000059604645,"error":-1}},{"atom":{"index":25,"h":"b"},"j":{"value":0.4000000059604645,"error":-1}}]},{"atom":{"index":20,"h":"a"},"shift":{"value":1.78000009059906,"error":0.2},"js":[{"atom":{"index":19,"h":"a"},"j":{"value":1.7999999523162842,"error":-1}},{"atom":{"index":21,"h":"a"},"j":{"value":3.200000047683716,"error":-1}},{"atom":{"index":21,"h":"b"},"j":{"value":3.200000047683716,"error":-1}},{"atom":{"index":22,"h":"a"},"j":{"value":3.0999999046325684,"error":-1}},{"atom":{"index":22,"h":"b"},"j":{"value":3.0999999046325684,"error":-1}}]},{"atom":{"index":21,"h":"a"},"shift":{"value":1.5500000715255737,"error":0.2},"js":[{"atom":{"index":16},"j":{"value":8.100000381469727,"error":-1}},{"atom":{"index":20,"h":"a"},"j":{"value":3.200000047683716,"error":-1}},{"atom":{"index":21,"h":"b"},"j":{"value":-13.199999809265137,"error":-1}}]},{"atom":{"index":21,"h":"b"},"shift":{"value":1.6900001764297485,"error":0.2},"js":[{"atom":{"index":16},"j":{"value":8.100000381469727,"error":-1}},{"atom":{"index":20,"h":"a"},"j":{"value":3.200000047683716,"error":-1}},{"atom":{"index":21,"h":"a"},"j":{"value":-13.199999809265137,"error":-1}}]},{"atom":{"index":22,"h":"a"},"shift":{"value":1.470000147819519,"error":0.2},"js":[{"atom":{"index":20,"h":"a"},"j":{"value":3.0999999046325684,"error":-1}},{"atom":{"index":22,"h":"b"},"j":{"value":-13.199999809265137,"error":-1}},{"atom":{"index":23,"h":"a"},"j":{"value":7.199999809265137,"error":-1}},{"atom":{"index":23,"h":"b"},"j":{"value":7.199999809265137,"error":-1}}]},{"atom":{"index":22,"h":"b"},"shift":{"value":1.6900001764297485,"error":0.2},"js":[{"atom":{"index":20,"h":"a"},"j":{"value":3.0999999046325684,"error":-1}},{"atom":{"index":22,"h":"a"},"j":{"value":-13.199999809265137,"error":-1}},{"atom":{"index":23,"h":"a"},"j":{"value":7.199999809265137,"error":-1}},{"atom":{"index":23,"h":"b"},"j":{"value":7.199999809265137,"error":-1}}]},{"atom":{"index":23,"h":"a"},"shift":{"value":2.630000352859497,"error":0.2},"js":[{"atom":{"index":22,"h":"a"},"j":{"value":7.199999809265137,"error":-1}},{"atom":{"index":22,"h":"b"},"j":{"value":7.199999809265137,"error":-1}},{"atom":{"index":23,"h":"b"},"j":{"value":-12.5,"error":-1}}]},{"atom":{"index":23,"h":"b"},"shift":{"value":3.380000352859497,"error":0.2},"js":[{"atom":{"index":22,"h":"a"},"j":{"value":7.199999809265137,"error":-1}},{"atom":{"index":22,"h":"b"},"j":{"value":7.199999809265137,"error":-1}},{"atom":{"index":23,"h":"a"},"j":{"value":-12.5,"error":-1}}]},{"atom":{"index":24,"h":"a"},"shift":{"value":5.7300004959106445,"error":0.2},"js":[{"atom":{"index":19,"h":"a"},"j":{"value":6.199999809265137,"error":-1}},{"atom":{"index":25,"h":"a"},"j":{"value":18.399999618530273,"error":-1}},{"atom":{"index":25,"h":"b"},"j":{"value":10.899999618530273,"error":-1}}]},{"atom":{"index":25,"h":"a"},"shift":{"value":5.006584644317627,"error":0.2},"js":[{"atom":{"index":19,"h":"a"},"j":{"value":0.4000000059604645,"error":-1}},{"atom":{"index":24,"h":"a"},"j":{"value":18.399999618530273,"error":-1}},{"atom":{"index":25,"h":"b"},"j":{"value":2,"error":-1}}]},{"atom":{"index":25,"h":"b"},"shift":{"value":5.006584644317627,"error":0.2},"js":[{"atom":{"index":19,"h":"a"},"j":{"value":0.4000000059604645,"error":-1}},{"atom":{"index":24,"h":"a"},"j":{"value":10.899999618530273,"error":-1}},{"atom":{"index":25,"h":"a"},"j":{"value":2,"error":-1}}]}]'),
		mol,
		nucleus = '1H',
		simParams = { nucleus: "1H", fromPPM: -2.0, toPPM: 10.0, size: 32768, frequency: 500.13, lineWidth: 0.75 };

	mol = new Molecule(Application.molecule.activeMolecule());
	if (!mol.isValid())
		throw "Invalid Molecule";

	mol.setNMRPrediction("1H", predObj);
	Application.NMRPredictor.createPredictedSpectrum(mol, simParams);
}

function setMoleculePredictionFromFile() {
	'use strict';
	var predStr = '',
		predObj,
		mol,
		nucleus = '1H',
		filename = FileDialog.getOpenFileName("*.json", "Select a prediction file", Dir.home()),
		file = new File(filename),
		simParams = { nucleus: "1H", fromPPM: -2.0, toPPM: 10.0, size: 32768, frequency: 500.13, lineWidth: 0.75 };
	if (filename.length === 0)
		return;
	if (Application.NMRPredictor === undefined)
		throw "Predictor Plugin not loaded";

	mol = new Molecule(Application.molecule.activeMolecule());
	if (mol.isValid() === false)
		throw "Invalid Molecule";

	if (file.open(File.ReadOnly)) {
		predStr = file.readAll();
		predObj = JSON.parse(predStr);
		Application.NMRPredictor.setPredictedValues(mol, "1H", predObj, simParams);
	}
}

function deprecatedPredictedMoleculeTest() {
	if (Application.NMRPredictor == undefined)
		throw "Predictor Plugin not loaded";

	var mol = new Molecule(Application.molecule.activeMolecule());
	if (mol.isValid() == false)
		throw "Invalid Molecule";

	var predictionResult = Application.NMRPredictor.predictionData(mol, "1H");
	if (predictionResult == undefined)
		throw "Molecule without prediction data";
	for (var i = 0; i < predictionResult.length; i++) {
		print(predictionResult[i].atom + predictionResult[i].H + ": " + predictionResult[i].shift);
		for (var j = 0; j < predictionResult[i].js.length; j++) {
			print("\t" + "J(" + predictionResult[i].atom + predictionResult[i].js[j].H1 + ", " + predictionResult[i].js[j].atom + predictionResult[i].js[j].H2 + "): " + predictionResult[i].js[j].value);
		}
	}
}

/* printerTest.qs */
function printerTest() {
	var printer = new Printer(Printer.ScreenResolution),
		w = mainWindow.activeDocument,
		pages = w.pages(),
		i = 0,
		addPage = false,
		file = FileDialog.getSaveFileName("Pdf (*.pdf)", "Save file");

	printer.paperSize = Printer.A4;//by default uses the one in the document
	printer.begin(file)
	for (i = pages.length - 1; i >= 0; --i) {
		if (addPage) {
			printer.newPage();
		} else {
			addPage = true;
		}
		printer.print(pages[i]);
	}
	printer.end();
}

/******************************************************************************************************
printHook.qs
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/*global Application, Env, Page, NMRSpectrum, print, Molecule*/

var printHook = {
	fTemplate: {
		'NMR Spectrum': {
			'background.opacity': 0,
			'grid.showhorizontal': false,
			'grid.showvertical': false,
			'curve.color': 'black',
			'curve.linewidth': 0,
			'axes.color': 'black',
			'integrals.curve.color': 'black',
			'integrals.label.color': 'black',
			'multiplets.fontcolor': 'black',
			'multiplets.integral.curve.color': 'black',
			'multiplets.integral.label.color': 'black',
			'peaks.color': 'black',
			'title.color': 'black'
		},
		'Molecule': { 'atomFontColor': 'black' }
	},

	fBackup: {},

	pageItems: function (aPagesIds) {
		'use strict';
		var page, i, activeDocument, items;

		items = [];
		activeDocument = Application.mainWindow.activeDocument;
		for (i = 0; i < aPagesIds.length; ++i) {
			page = new Page(activeDocument.page(aPagesIds[i]));
			items = items.concat(page.items);
		}
		return items;
	},

	updateItem: function (aItem) {
		'use strict';
		var id, name, props, p, backupData, nmrSpc, molecule;

		backupData = {};
		name = aItem.name;
		id = aItem.uuid;
		props = this.fTemplate[name];
		if (props !== undefined) {
			if (name === 'NMR Spectrum') {
				nmrSpc = new NMRSpectrum(aItem);
				if (nmrSpc.isValid()) {
					for (p in props) {
						if (props.hasOwnProperty(p)) {
							try {
								print(p + ' ' + nmrSpc.getProperty(p));
								backupData[p] = nmrSpc.getProperty(p);
								nmrSpc.setProperty(p, props[p]);
								print(p + ' ' + nmrSpc.getProperty(p));
							} catch (er) {
								print(p + ' ' + er);
							}
						}
					}
					this.fBackup[id] = backupData;
				}
			} else if (name === 'Molecule') {
				molecule = new Molecule(aItem);
				if (molecule.isValid()) {
					this.fBackup[id] = molecule.graphicProperties();
					print(this.fBackup[id]);
					molecule.setGraphicProperties(props);
					print(molecule.graphicProperties());
				}
			}
			return true;
		}
		return false;
	},

	beforePrinting: function (aJSONString) {
		'use strict';
		var args, items, i, item, needsUpdate;

		print("Before Printing");
		print(aJSONString);
		args = JSON.parse(aJSONString);

		needsUpdate = false;
		items = this.pageItems(args.pageIds);
		for (i = 0; i < items.length; ++i) {
			item = items[i];
			needsUpdate = this.updateItem(item);
		}
		return true;
	},

	afterPrinting: function (aJSONArgs) {
		'use strict';
		var id, props, activeDocument, item, nmrSpc, p, molecule;

		print("After Printing");
		activeDocument = Application.mainWindow.activeDocument;
		for (id in this.fBackup) {
			if (this.fBackup.hasOwnProperty(id)) {
				item = activeDocument.getItem(id);
				if (item.isValid()) {
					props = this.fBackup[id];
					if (item.name === "NMR Spectrum") {
						nmrSpc = new NMRSpectrum(item);
						if (nmrSpc.isValid()) {
							for (p in props) {
								if (props.hasOwnProperty(p)) {
									try {
										print(p + ' ' + nmrSpc.getProperty(p));
										nmrSpc.setProperty(p, props[p]);
										print(p + ' ' + nmrSpc.getProperty(p));
									} catch (er) {
										print(p + ': ' + er);
									}
								}
							}
						}
					} else if (item.name === "Molecule") {
						molecule = new Molecule(item);
						if (molecule.isValid()) {
							print(molecule.graphicProperties());
							molecule.setGraphicProperties(props);
							print(molecule.graphicProperties());
						}
					}
				}
			}
		}
		return true;
	}
};

function printHookTest() {
	'use strict';
	var pages, activeDocument;

	activeDocument = Application.mainWindow.activeDocument;
	pages = JSON.stringify({ 'pageIds': activeDocument.pagesIds() });
	printHook.beforePrinting(pages);
	printHook.afterPrinting(pages);
}

Application.mainWindow.installEventHandler("beforePrinting", "printHook.beforePrinting");
Application.mainWindow.installEventHandler("afterPrinting", "printHook.afterPrinting");

/******************************************************************************************************
process_each_opened_spectrum.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
// This example function demonstrates how to apply some processing to the spectra already opened in MestReNova. 
// It applies a specific processing dependently on the spectrum nucleus and dimensionality values.
function process_each_opened_spectrum() {
	var dw = new DocumentWindow(Application.mainWindow.activeWindow());
	var pageCount = dw.pageCount();
	for (var i = 0; i < pageCount; i++) {
		var page = new Page(dw.page(i));
		var itemCount = page.itemCount();
		for (var j = 0; j < itemCount; j++) {
			var spec = new NMRSpectrum(page.item(j));
			if (spec.isValid()) // if page item is a spectrum
			{
				print("Item #" + j + " is " + spec.dimCount + "D spectrum.");
				var processing = new String;
				if (spec.dimCount == 1) {
					if (spec.nucleus() == "1H")
						processing = "c:/process/_test.mnp";
					else if (spec.nucleus() == "13C")
						processing = "c:/process/13C.mnp";
				}
				else if (spec.dimCount == 2) {
					if (spec.nucleus(1) == "1H" && spec.nucleus(2) == "1H")
						processing = "c:/process/COSY.mnp";
				}
				if (!processing.isEmpty())
					nmr.processSpectrum(spec, processing);
				else
					print("Spectrum #" + j + " was not processed.");
			}
			else {
				print("Item #" + j + " is not a spectrum.")
			}
		}
	}
}

/*******************************************************************************************
processTest.qs
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/
/*jslint  */
/*global File, Process, print, Dir, TextStream*/

function processTest() {
	'use strict';
	var fileName,
		f,
		s;
	fileName = Dir.temp() + "/MNova_Process_Text.txt";
	f = new File(fileName);
	f.open(File.WriteOnly);
	s = new TextStream(f);
	s.write("Hello Notepad!");
	f.close();
	print(Process.execute("notepad.exe", fileName));

	f.open(File.ReadWrite);
	s.pos = f.size;
	print(s);
	s.write("\r\nHi again!");
	f.close();
	print(Process.startDetached("notepad.exe", fileName));
}

function processTestAdv() {
	'use strict';
	var proc = new Process();

	proc.started.connect(function () { MessageBox.information("Process Started!"); });
	proc["finished(int)"].connect(proc, function (aExitCode, aStatus) { MessageBox.information("Process Finished. Exit Code %1.".arg(aExitCode)); print(this.allStdOutput); print(this.allErrorOutput); });
	proc.start('ls', ['-lh', '/home/']);
	if (!proc.waitForStarted()) {
		MessageBox.critical("Failed to Start");
	}
}

// <GUI menuname="Report Parameters and PDF" tooltip="Report Parameters and PDF"/>

/******************************************************************************************************
reportParametersAndPDF.qs
Copyright (C) 2009 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function reportParametersAndPDF() {
	if (reportParametersAndLayout(true)) //set parameter to false not to add the spectrum title
		mainWindow.doAction("action_File_ExportToPDF");
}

function getTitleString(aSpectrum) {
	var titleString = "<b>%1</b>";
	var spectrumTitle = aSpectrum.getParam("Title");
	var splitTitle = spectrumTitle.split("\n");//we only want the first line of the title
	var removeRegExp = new RegExp(";$");//removes ";" at the end of the title
	return titleString.replace("%1", splitTitle[0].replace(removeRegExp, ""));
}

function reportParametersAndLayout(addTitle) {
	var dw = new DocumentWindow(mainWindow.activeWindow());
	var cP = new Page(dw.curPage());
	//Select the first NMR Spectrum
	var spcItem = cP.item(0, "NMR Spectrum");
	if (!spcItem.isValid())
		return false;
	dw.setSelection(spcItem);
	//Is there a previous report?
	var reportItem = undefined;
	var textItem = undefined;
	var rExp = new RegExp('^Parameters,.*');
	for (var i = 0; i < cP.itemCount("Text"); i++) {
		textItem = cP.item(i, "Text");
		if (textItem.type == "NMR Table" && rExp.test(textItem.subtype)) {
			hasReport = true;
			reportItem = textItem;
		}
	}
	//If not, create one
	if (reportItem == undefined) {
		mainWindow.doAction("NMRParametersTable::action_Report");
		reportItem = cP.item(0, "Text");
	}
	//Layout the new list of items
	var titleItem = undefined;
	if (addTitle == true) {
		//Get title
		var titleString = getTitleString(nmr.activeSpectrum());
		titleItem = draw.text(titleString, true);
		titleItem.left = (cP.left + cP.right - titleItem.width) / 2.0;
	}
	spcItem.width = 2.0 * cP.width / 3.0;
	if (titleItem == undefined)
		spcItem.top = cP.top;
	else
		spcItem.top = titleItem.bottom;
	spcItem.bottom = cP.bottom;
	reportItem.left = spcItem.right;
	reportItem.top = spcItem.top;
	reportItem.width = cP.width / 3.0;
	reportItem.bottom = cP.bottom;

	spcItem.update();
	reportItem.update();
	dw.update();
	return true;
}

/******************************************************************************************************
scriptCustom.qs
Copyright (C) 2012 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/** Script Ui Example
 * If Mnova finds a valid *.mui file in the scripts directories (e.g. scriptCustom.mui) a script object with the same basename (scriptCustom) will be created automatically and added as a property to the global object MnUi (MnUi.scriptCustom)
 * To run each one of the actions defined in the mui file, Mnova will try to run a function inside the custom ui object with the same name as the action. (MnUi.scriptCustom.actionName)
 * Moreover, Mnova will use two default functions(if they exist): 
 * init() to be called when Mnova starts after loading the default scripts (MnUi.scriptCustom.init())
 * update(aUpdateObj) to be called everytime the UI needs and update (MnUi.scriptCustom.update(aUpdateObj)). The aUpdateObj properties are called in the same way as the actions in the mui file having as properties standard UI properties (enabled, checked, text, tooltip, visible...), modifying them will modify the UI.
 * All the above functions will be called with the same this object so it's possible to set an internal state to the MnUi.scriptCustom object.
 */

//! Init function, we add our custom variables.
MnUi.scriptCustom.init = function () {
	print("Init scriptCustom")
	this.fEnabled1 = true
	this.fEnabled2 = true
}

//! Update function. aUpdateActionObj has as properties the actions defined in the mui file.
MnUi.scriptCustom.update = function (aUpdateObj) {
	print("Update actions")
	print(this.fEnabled1 + " " + this.fEnabled2)
	aUpdateObj.scriptCustomAction.enabled = this.fEnabled1
	if (aUpdateObj.scriptCustomAction.enabled)
		aUpdateObj.scriptCustomAction.text = "Show a Dialog..."
	else
		aUpdateObj.scriptCustomAction.text = "Disabled"
	aUpdateObj.scriptCustomAction2.checked = this.fEnabled1
	aUpdateObj.scriptCustomAction2.enabled = this.fEnabled2
	aUpdateObj.scriptCustomAction3.checked = this.fEnabled2
}

//! This function will be called when the mui file action "scriptCustomAction" is triggered
MnUi.scriptCustom.scriptCustomAction = function () {
	print("scriptCustomAction2")
	MessageBox.information("You Pressed the Button", MessageBox.Ok)
}

//! The internal state of the this object can be modified as a result of one action
MnUi.scriptCustom.scriptCustomAction2 = function () {
	print("scriptCustomAction2")
	this.fEnabled1 = !this.fEnabled1
	var message = ""
	if (this.fEnabled1)
		message = "Action 1 Enabled"
	else
		message = "Action 1 Disabled"
	MessageBox.information(message, MessageBox.Ok)
}

MnUi.scriptCustom.scriptCustomAction3 = function () {
	print("scriptCustomAction3")
	this.fEnabled2 = !this.fEnabled2
	var message = ""
	if (this.fEnabled2)
		message = "Action 2 Enabled"
	else
		message = "Action 2 Disabled"
	MessageBox.information(message, MessageBox.Ok)
}

/******************************************************************************************************
selectionTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function selectionTest() {
	var dw = new DocumentWindow(mainWindow.activeWindow());
	var cP = new Page(dw.curPage());
	var itemList = new Array(cP.itemCount());
	for (var i = 0; i < cP.itemCount(); i++)
		itemList[i] = cP.item(i);
	dw.setSelection(itemList);
	//dw.setSelection(itemList[1])
	dw.setActive(itemList[0]);

	var sel = dw.selection();
	print("Items selected: " + sel.length);
	for (var i = 0; i < sel.length; i++)
		print(sel[i]);
	dw.update();
}

/******************************************************************************************************
sendEmail.qs
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/*globals settings, Dir, MessageBox, qsTr, File, print, Application, WebUtils, FileDialog, mainWindow*/
/*jslint plusplus: true, continue: true, bitwise: true*/


function sendEmail() {
	"use strict";
	var i, items, email, showDialog, showSettingsDialog, webUtils, res, text, ssl,
		toKey = "Send Email/To",
		fromKey = "Send Email/From",
		subjectKey = "Send Email/Subject",
		passwordKey = "Send Email/Password",
		loginKey = "Send Email/Account",
		serverKey = "Send Email/Server",
		portKey = "Send Email/Port",
		sSLSKey = "Send Email/SSL",
		authTypeKey = "Send Email/Auth Type",
		lastAttachementFolderKey = "Send Email/Last Folder",
		isHTMLKey = "Send Email/Is HTML",
		dialog = Application.loadUiFile("ricares:sendEmail.ui"),
		settingsDialog = Application.loadUiFile("ricares:sendEmailSettings.ui"),
		server = {},
		debugMode = false,
		files = [],
		currentRow = -1;


	function obfuscatePassword(aString) {

		var newPassword = [];

		for (i = 0; i < aString.length; i++) {
			newPassword.push(aString.charCodeAt(i) + i);
		}
		return JSON.stringify(newPassword);
	}

	function deobfuscatePassword(aString) {
		var pass = "";

		if (aString && aString.length) {
			try {
				aString = JSON.parse(aString);
			} catch (ERR) {
				return "";
			}

			for (i = 0; i < aString.length; i++) {
				pass += String.fromCharCode(aString[i] - i);
			}

		}
		return pass;
	}

	function setServerSettings() {
		var pass, data;

		showSettingsDialog = true;
		settingsDialog.widgets.leServer.text = settings.value(serverKey, "");
		settingsDialog.widgets.leLogin.text = settings.value(loginKey, "");
		pass = settings.value(passwordKey, " ");

		data = settings.value(portKey, "");
		if (data !== "") {
			settingsDialog.widgets.spbxMailPort.value = data;
		}

		data = settings.value(sSLSKey, "");
		if (data !== "") {
			data = (data === "true");
			settingsDialog.widgets.chbxMailSSL.checked = data;
		}

		data = settings.value(authTypeKey, "-");
		if (data !== "-") {
			settingsDialog.widgets.cbMailAuthentication.currentIndex = data;
		}

		if (pass && pass !== "") {
			settingsDialog.widgets.lePassword.text = deobfuscatePassword(pass);
		}

		while (showSettingsDialog) {
			if (!settingsDialog.exec()) {
				return;
			}

			if (settingsDialog.widgets.leServer.text === "" || settingsDialog.widgets.leLogin.text === "") {
				MessageBox.information(qsTr("Server and login are needed"));
			} else {
				showSettingsDialog = false;
			}
		}

		settings.setValue(serverKey, settingsDialog.widgets.leServer.text);
		settings.setValue(loginKey, settingsDialog.widgets.leLogin.text);
		settings.setValue(passwordKey, obfuscatePassword(settingsDialog.widgets.lePassword.text));
		settings.setValue(portKey, settingsDialog.widgets.spbxMailPort.text);
		settings.setValue(sSLSKey, settingsDialog.widgets.chbxMailSSL.checked);
		settings.setValue(authTypeKey, settingsDialog.widgets.cbMailAuthentication.currentIndex);
	}

	function getServerSettings() {
		var server, login, password, data, port, ssl, authType, serverObject;

		server = settings.value(serverKey, "");
		login = settings.value(loginKey, "");
		password = deobfuscatePassword(settings.value(passwordKey, " "));

		data = settings.value(portKey, "");
		if (data !== "") {
			port = data;
		}

		data = settings.value(sSLSKey, "");
		if (data !== "") {
			data = (data === "true");
			ssl = data;
		}

		data = settings.value(authTypeKey, "-");
		if (data !== "-") {
			authType = data;
		}

		serverObject = { server: server, login: login, password: password, port: port, authentication: authType, ssl: ssl };

		return serverObject;
	}
	function saveDataToRegistry() {
		settings.setValue(fromKey, dialog.widgets.leFrom.text);
		settings.setValue(toKey, dialog.widgets.leTo.text);
		settings.setValue(subjectKey, dialog.widgets.leSubject.text);
	}

	function getDataFromRegistry() {
		dialog.widgets.leFrom.text = settings.value(fromKey, "");
		dialog.widgets.leTo.text = settings.value(toKey, "");
		dialog.widgets.leSubject.text = settings.value(subjectKey, "");
	}

	dialog.widgets.btSettings.clicked.connect(function () {
		setServerSettings();
	});

	dialog.widgets.btAddAttachement.clicked.connect(function () {

		var items, file = FileDialog.getOpenFileName("*", "Select file", settings.value(lastAttachementFolderKey, settings.value(lastAttachementFolderKey, Dir.home())));

		if (file.length) {
			dialog.widgets.twAttachements.insertRow(0);
			items = dialog.widgets.twAttachements.items;
			items[0][0].text = file;
			items[0][0].flags = 35;
			dialog.widgets.twAttachements.items = items;
			file = new File(file);
			settings.setValue(lastAttachementFolderKey, file.absDirPath);
			currentRow = 0;
		}
	});

	dialog.widgets.twAttachements.cellClicked.connect(function (row) {
		currentRow = row;
	});

	dialog.widgets.btRemoveAttachement.clicked.connect(function () {
		dialog.widgets.twAttachements.removeRow(currentRow);
		currentRow = -1;
	});

	dialog.widgets.cbHTML.stateChanged.connect(function (state) {
		dialog.widgets.teText.acceptRichText = state;
		if (state) {
			dialog.widgets.cbSource.enabled = true;
			if (dialog.widgets.cbSource.checked) {
				dialog.widgets.teText.plainText = dialog.widgets.teText.html;
			}
		} else {
			dialog.widgets.cbSource.enabled = false;
			dialog.widgets.teText.html = dialog.widgets.teText.plainText;
		}

	});

	dialog.widgets.cbSource.stateChanged.connect(function (state) {
		if (state) {
			dialog.widgets.teText.acceptRichText = false;
			dialog.widgets.teText.plainText = dialog.widgets.teText.html;
		} else {
			dialog.widgets.teText.acceptRichText = true;
			dialog.widgets.teText.html = dialog.widgets.teText.plainText;

		}

	});


	showDialog = true;

	dialog.widgets.cbHTML.checked = settings.value(isHTMLKey, true);


	if (debugMode) {
		getDataFromRegistry();
	}

	while (showDialog) {
		if (!dialog.exec()) {
			return;
		}

		if (dialog.widgets.leFrom.text === "") {
			MessageBox.critical(qsTr("From field is needed"));
			dialog.widgets.leFrom.setFocus();
			continue;
		}

		if (dialog.widgets.leTo.text === "") {
			MessageBox.critical(qsTr("To field is needed"));
			dialog.widgets.leTo.setFocus();
			continue;
		}

		server = getServerSettings();

		if (!server || !server.server || !server.login) {
			MessageBox.critical(qsTr("Server settings are not available. Please, configure your account and try again"));
			continue;
		}

		if (debugMode) {
			saveDataToRegistry();
		}

		settings.setValue(isHTMLKey, dialog.widgets.cbHTML.checked);

		webUtils = new WebUtils();
		if (!webUtils.isValid) {
			MessageBox.information(qsTr("Error initializing WebUtils"));
			return;
		}

		items = dialog.widgets.twAttachements.items;

		for (i = 0; i < items.length; i++) {
			files.push(items[i][0].text);
		}

		if (dialog.widgets.teText.acceptRichText) {
			text = dialog.widgets.teText.html;
		} else {
			text = dialog.widgets.teText.plainText;
		}

		email = { from: dialog.widgets.leFrom.text, to: dialog.widgets.leTo.text.split(","), subject: dialog.widgets.leSubject.text, text: text, files: files, isHtml: dialog.widgets.cbHTML.checked };
		try {
			mainWindow.setWaitCursor();
			mainWindow.processEvents();
			ssl = server.ssl;
			server.ssl = undefined;
			res = webUtils.sendEmail(email, server, ssl);
			mainWindow.restoreCursor();

			if (res.exitCode === 0) {
				MessageBox.information(qsTr("Your email was sent successfully"));
				showDialog = false;
			} else {
				MessageBox.critical(qsTr("Error sending mail: {0}").format(res.allErrorOutput));
			}

		} catch (ERR) {
			MessageBox.critical(ERR);
			mainWindow.restoreCursor();
		}

	}

}

/*******************************************************************************
 seriralizeTest.qs
 * Copyright (C) 2018 Mestrelab Research S.L. All rights reserved.
 *
 * This file is part of the MNova scripting toolkit.
 *
 * Authorized users of MNova Software may use this file freely, but this file is 
 * provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 * ****************************************************************************/

/*jslint plusplus: true, nomen: true, indent: 4, white: true*/
/*global qsTr, ByteArray, BinaryStream, File, print*/


function serializeTest() {
	'use strict';

	var obj = {
		num: 12,
		floatNum: 3.14159,
		str: "Custom String",
		utf8Str: "Николай",
		"Николай": "Utf8Key",
		arr: [1, "2", 3],
		boolParam: true,
		nullObj: null,
		undefObj: undefined,
		internalObj: { key: "Custom Value", key2: "Another Key" },
		customFunction: function () { print("Hello"); }, //should not be serialized
		qObj: new ByteArray("Some Text") //only properties should be serialized
	}, strm, bArr = new ByteArray(), newObj;

	//uncommenting this should throw an recursive storing error
	//obj.arr.push(obj);

	strm = new BinaryStream(bArr);
	strm.writeObj(obj);
	print("ByteArray size: {0}".format(bArr.size));

	strm.pos = 0;
	newObj = strm.readObj();

	print("Read object:");
	print(JSON.stringify(newObj, null, " "));
}

function CustomCtor() {
	'use strict';

	this.num = 0;
	this.floatNum = 0.0;
}

CustomCtor.prototype.constructorName = "CustomCtor";

CustomCtor.prototype.storeObj = function (aStr) {
	'use strict';
	aStr.writeString(JSON.stringify(this));
};

CustomCtor.prototype.loadObj = function (aStr) {
	'use strict';

	var str = aStr.readString(),
		loaded = JSON.parse(str);

	Object.keys(loaded).forEach(function (aK) {
		this[aK] = loaded[aK];
	}, this);
};

function customSerializeTest() {
	'use strict';

	var obj = new CustomCtor(),
		bArr = new ByteArray(), strm = new BinaryStream(bArr), newObj;

	obj.num = 3;
	obj.floatNum = 3.14159;

	strm.writeObj(obj);

	print("ByteArray size: {0}".format(bArr.size));

	strm.pos = 0;
	newObj = strm.readObj();

	print("Read object:");
	print(JSON.stringify(newObj, null, " "));
}

/* setTraces.qs */
//Expects a document with two NMR Spectrums, one 1D and one 2D. Sets both traces of the 2D to be the 1D spectrum
function setTraces() {
	var actWindow = mainWindow.activeWindow();
	var curPage = actWindow.curPage();
	var numberOfNMRItems = actWindow.itemCount("NMR Spectrum");
	if (numberOfNMRItems == 2) //to avoid more checks only works with 2 NMR Items in the document
	{
		var spc2D = undefined;
		var spc1D = undefined;

		var firstItem = new NMRSpectrum(actWindow.item(0, "NMR Spectrum"));
		if (firstItem.dimCount == 1)
			spc1D = firstItem;
		else
			spc2D = firstItem;

		var secondItem = new NMRSpectrum(actWindow.item(1, "NMR Spectrum"));
		if (secondItem.dimCount == 1)
			spc1D = secondItem;
		else
			spc2D = secondItem;

		if (spc2D != undefined && spc1D != undefined) {
			spc2D.setTrace(spc1D, true);//sets horizontal trace
			spc2D.setTrace(spc1D, false);//sets vertical trace
			spc2D.update();
			curPage.update();
			actWindow.update();
		}
	}
}

/******************************************************************************************************
spectrumParams.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function spectrumParams() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	print(spec.getParam("Nucleus[1]"));
	print(spec.getParam("Spectrometer Frequency"));
}

/*******************************************************************************************
spectrumZoom.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/
function spectrumZoom() {
	var spc = nmr.activeSpectrum();
	if (!spc.isValid())
		return;
	spc.horzZoom(1.0, 5.0);
	spc.vertZoom(1.0, 5.0);
	/*if( spc.dimCount == 1 )
		spc.zoom(3.0, 4.5);
	else
		spc.zoom(1.0, 5.0, 1.0, 5.0);*/
	//spc.zoom();
	spc.update();
	mainWindow.activeWindow().update();
}

/******************************************************************************************************
spinSimulationTest.qs
Copyright (C) 2010 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
function spinSimulationTest() {
	if (Application.NMRPredictor == undefined)
		throw "Predictor Plugin not loaded";

	var filename = FileDialog.getOpenFileName("XML Files(*.xml);;All files (*.*)", "Select Simulation File");
	if (filename != undefined) {
		var file = new File(filename);
		if (file.open(File.ReadOnly)) {
			var txtStrm = TextStream(file);
			var xmlString = new String(txtStrm.readAll());
			Application.NMRPredictor.loadSimulation(xmlString);
		}
		else {
			MessageBox.critical("Unable to Open File", MessageBox.Ok);
		}
	}
	else {
		MessageBox.critical("Error Loading Simulation", MessageBox.Ok);
	}
}

//<GUI menuname="Split SDFile..." tooltip="Split an SDFile into several files"/>

/******************************************************************************************************
splitSDFile.qs
Copyright (C) 2009 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/*globals FileDialog, settings, Dir, File, Dialog, print, ComboBox, SpinBox, LineEdit, ToolButton, GroupBox, CheckBox, TextStream, MessageBox, mainWindow,
Serialization, Str*/
/*jslint plusplus: true, indent: 4, continue: true, bitwise: true*/

function splitSDFile() {
	"use strict";

	var inDirSettingsKey = "Split SDFile/Input Directory",
		outDirSettingsKey = "Split SDFile/Output Directory",
		outFormatSettingsKey = "Split SDFile/Output Format",
		chunkSizeSettingsKey = "Split SDFile/Chunk Size",
		useHeaderSettingsKey = "Split SDFile/Use Header",
		useTagSettingsKey = "Split SDFile/Use Tag",
		tagSettingsKey = "Split SDFile/Tag",
		inFileName,
		dialog,
		dirName,
		cbFormat,
		sbChunkSize,
		leDirectory,
		tbOpenDir,
		gbFolder,
		chUseHeader,
		chUseTag,
		leTag,
		outDirName,
		outFormat,
		chunkSize,
		useHeader,
		useTag,
		tag,
		startTime,
		inFile,
		s,
		inStream,
		dw,
		ok,
		outFileCount,
		chunkCount,
		buffer,
		endConnectionTableWritten,
		tagFileName,
		readingTag,
		serialization,
		line,
		outFileName;

	inFileName = FileDialog.getOpenFileName("SDfile (*.sdf);;All files (*.*)", "Select File", settings.value(inDirSettingsKey, Dir.home()));
	if (!inFileName.length) {
		return;
	}
	settings.setValue(inDirSettingsKey, File.absDirPath(inFileName));

	dialog = new Dialog("Output Options");
	dialog.onOpenDir = function () {
		dirName = FileDialog.getExistingDirectory(this.text);
		print("Directory: " + dirName);
		if (dirName.length > 0) {
			this.text = dirName;
		}
	};

	dialog.onCBFormatChanged = function () {
		if (this.currentText === "mol") {
			this.oldValue = sbChunkSize.value;
			sbChunkSize.maximum = 1;
			sbChunkSize.value = 1;
		} else {
			sbChunkSize.maximum = 65535;
			if (typeof (this.oldValue) === "number") {
				sbChunkSize.value = this.oldValue;
			}
		}
	};

	cbFormat = new ComboBox();
	cbFormat.addItem("mnova");
	cbFormat.addItem("mol");
	cbFormat.addItem("sdf");
	cbFormat['activated(QString)'].connect(cbFormat, dialog.onCBFormatChanged);
	cbFormat.currentIndex = settings.value(outFormatSettingsKey, 0);

	sbChunkSize = new SpinBox();
	sbChunkSize.minimum = 1;
	sbChunkSize.maximum = 65535;
	sbChunkSize.value = settings.value(chunkSizeSettingsKey, 1);

	leDirectory = new LineEdit();
	leDirectory.label = "Directory:";
	leDirectory.text = settings.value(outDirSettingsKey, Dir.home());

	tbOpenDir = new ToolButton();
	tbOpenDir.text = "...";
	tbOpenDir.clicked.connect(leDirectory, dialog.onOpenDir);

	gbFolder = new GroupBox();
	gbFolder.title = "Output";
	gbFolder.add("Format:", cbFormat);
	gbFolder.add("Chunk size:", sbChunkSize);
	gbFolder.add(leDirectory, tbOpenDir);
	dialog.add(gbFolder);

	chUseHeader = new CheckBox();
	chUseHeader.text = "Use header for file name";
	chUseHeader.checked = settings.value(useHeaderSettingsKey, false);

	dialog.add(chUseHeader);

	chUseTag = new CheckBox();
	chUseTag.text = "Use tag for file name";
	chUseTag.checked = settings.value(useTagSettingsKey, false);

	leTag = new LineEdit();
	leTag.text = settings.value(tagSettingsKey, "1234");

	if (chUseTag.checked) {
		leTag.enabled = true;
	} else {
		leTag.enabled = false;
	}

	chUseHeader.stateChanged.connect(function (checked) {
		if (checked === 2) {
			chUseTag.checked = false;
			leTag.enabled = false;
		}
	});

	chUseTag.stateChanged.connect(function (checked) {
		if (checked === 2) {
			chUseHeader.checked = false;
			leTag.enabled = true;
		} else {
			leTag.enabled = false;
		}
	});

	dialog.add(chUseTag, leTag);

	if (!dialog.exec()) {
		return undefined;
	}

	outDirName = leDirectory.text;
	outFormat = cbFormat.currentText;
	chunkSize = sbChunkSize.value;
	useHeader = chUseHeader.checked;
	useTag = chUseTag.checked;
	tag = leTag.text;

	if (!outDirName.length) {
		return;
	}

	settings.setValue(outDirSettingsKey, outDirName);
	settings.setValue(outFormatSettingsKey, cbFormat.currentIndex);
	settings.setValue(chunkSizeSettingsKey, chunkSize);
	settings.setValue(useHeaderSettingsKey, useHeader);
	settings.setValue(useTagSettingsKey, useTag);
	settings.setValue(tagSettingsKey, tag);

	// Converts number to string, padding with leading 0's
	function pad(aNumber) {
		var result = "" + aNumber;
		while (result.length < 6) {
			result = "0" + result;
		}
		return result;
	}

	// Saves given array of lines to temporary sdf file and read temporary file into mnova.
	function processBuffer(aLines, aFileName) {
		var outStream, l, ok = true,
			tempFile = new File(aFileName);

		tempFile.open(File.WriteOnly);
		outStream = new TextStream(tempFile);
		for (l = 0; l < aLines.length; l++) {
			outStream.writeln(aLines[l]);
		}
		tempFile.close();
		// Open temporary file and read contents
		if (s.open(aFileName, "SDfile (*.sdf)")) {
			tempFile.remove();
		} else {
			MessageBox.critical("Could not open file '" + aFileName + "'.");
			ok = mainWindow.waitForInput("Continue with conversion?");
			mainWindow.setBusy("Working...");
		}
		return ok;
	}

	// Process file
	startTime = new Date();
	print("It is now " + startTime.toString());

	inFile = new File(inFileName);
	if (!inFile.open(File.ReadOnly)) {
		MessageBox.critical("Could not open file '" + inFileName + "'.");
		return;
	}
	inStream = new TextStream(inFile);

	s = new Serialization(serialization);
	s.fileHistory = false;

	dw = mainWindow.newWindow();
	ok = true;
	outFileCount = 0;
	chunkCount = 0;
	buffer = [];
	endConnectionTableWritten = false;
	tagFileName = "";
	readingTag = false;

	while (!inStream.atEnd() && ok) {
		line = inStream.readLine();
		//print("'" + line + "'");

		if (readingTag) {
			if (line.indexOf("> <") === -1) {
				tagFileName += line;
			} else {
				readingTag = false;
			}
		}

		if (useTag) {
			if (line === "> <" + tag + ">") {
				readingTag = true;
			}
		}

		if (line === "$$$$") {
			mainWindow.setStatusMessage("Processing structure " + outFileCount + " ...");
			// EGW1539: Add "M END" to connection table
			if (!endConnectionTableWritten) {
				buffer.push("M  END");
			}
			buffer.push("$$$$");
			endConnectionTableWritten = false;
			// Write temporary file and  re-read into Mnova
			ok = processBuffer(buffer, Dir.temp() + "/" + Str.fileNameFromPath(inFileName) + "-" + pad(outFileCount) + ".sdf");
			outFileCount++;
			// Write output file every chunkSize items
			if (((outFileCount % chunkSize) === 0) && ok) {
				outFileName = outDirName + "/";

				if (useHeader) {
					outFileName += Str.trimStr(buffer[0]);
				} else if (useTag) {
					if (tagFileName !== "") {
						outFileName += tagFileName;
					} else {
						outFileName += "tagNotFound_" + Str.fileNameFromPath(inFileName) + "-" + (chunkSize > 1 ? pad(chunkCount * chunkSize + 1) + "-" : "") + pad(outFileCount);
					}
				} else {
					outFileName += Str.fileNameFromPath(inFileName) + "-" + (chunkSize > 1 ? pad(chunkCount * chunkSize + 1) + "-" : "") + pad(outFileCount);
				}
				outFileName += "." + outFormat;
				mainWindow.setStatusMessage("Writing " + outFileName + "...");
				//print("Writing file " + outFileName);
				dw.setSelectedPages(dw.pages()); // Select all pages in document, needed for saving all molecules into sdf
				s.save(outFileName, outFormat);
				tagFileName = "";
				dw.close();
				dw = mainWindow.newWindow();
				chunkCount++;
			}
			// Looks better in mnova if each molecule goes onto a new page
			if (chunkSize > 1) {
				dw.newPage();
			}
			// Prepare buffer for next molecule
			buffer = [];
		} else if (line === "M END" || line === "M  END") {
			buffer.push("M  END");
			endConnectionTableWritten = true;
		} else {
			if (line.substr(0, 1) === ">" && !endConnectionTableWritten) {
				// EGW1539: Add "M END" to connection table
				buffer.push("M  END");
				endConnectionTableWritten = true;
			}
			buffer.push(line);
		}
	}
	// Write remaining items
	if ((buffer.length > 0) && ok) {
		outFileName = outDirName + "/";
		if (useHeader) {
			outFileName += Str.trimStr(buffer[0]);
		} else if (useTag) {
			if (tagFileName !== "") {
				outFileName += tagFileName;
			} else {
				outFileName += "tagNotFound_" + Str.fileNameFromPath(inFileName) + "-" + (chunkSize > 1 ? pad(chunkCount * chunkSize + 1) + "-" : "") + pad(outFileCount);
			}
		} else {
			outFileName += Str.fileNameFromPath(inFileName) + "-" + (chunkSize > 1 ? pad(chunkCount * chunkSize + 1) + "-" : "") + pad(outFileCount);
		}
		outFileName += "." + outFormat;
		//mainWindow.setStatusMessage("Writing " + outFileName + "...");
		//print("Writing file " + outFileName);
		dw.setSelectedPages(dw.pages()); // Select all pages in document, needed for saving all molecules into sdf
		s.save(outFileName, outFormat);
		dw.close();
	}
	// All done
	inFile.close();
	mainWindow.endBusy();
	print("All done in " + ((new Date() - startTime) / 1000) + " seconds.");
}


/******************************************************************************************************
tableWidgetExample.qs
Copyright (C) 2015 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function tableWidgetExample() {
	var ui = '<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"><class>Dialog</class><widget class="QDialog" name="Dialog"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>300</height></rect></property><property name="windowTitle"><string>Dialog</string></property><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QTableWidget" name="tableWidget"><row><property name="text"><string>0</string></property></row><row><property name="text"><string>1</string></property></row><row><property name="text"><string>2</string></property></row><row><property name="text"><string>3</string></property></row><column><property name="text"><string>0</string></property></column><column><property name="text"><string>1</string></property></column><column><property name="text"><string>2</string></property></column><column><property name="text"><string>3</string></property></column><item row="0" column="0"><property name="text"><string>00</string></property></item><item row="0" column="1"><property name="text"><string>01</string></property></item><item row="0" column="2"><property name="text"><string>02</string></property></item><item row="0" column="3"><property name="text"><string>03</string></property></item><item row="1" column="0"><property name="text"><string>10</string></property></item><item row="1" column="1"><property name="text"><string>11</string></property></item><item row="1" column="2"><property name="text"><string>12</string></property></item><item row="1" column="3"><property name="text"><string>13</string></property></item><item row="2" column="0"><property name="text"><string>20</string></property></item><item row="2" column="1"><property name="text"><string>21</string></property></item><item row="2" column="2"><property name="text"><string>22</string></property></item><item row="2" column="3"><property name="text"><string>23</string></property></item><item row="3" column="0"><property name="text"><string>30</string></property></item><item row="3" column="1"><property name="text"><string>31</string></property></item><item row="3" column="2"><property name="text"><string>32</string></property></item><item row="3" column="3"><property name="text"><string>33</string></property></item></widget></item><item><widget class="QDialogButtonBox" name="buttonBox"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="standardButtons"><set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set></property></widget></item></layout></widget><resources/><connections><connection><sender>buttonBox</sender><signal>accepted()</signal><receiver>Dialog</receiver><slot>accept()</slot><hints><hint type="sourcelabel"><x>248</x><y>254</y></hint><hint type="destinationlabel"><x>157</x><y>274</y></hint></hints></connection><connection><sender>buttonBox</sender><signal>rejected()</signal><receiver>Dialog</receiver><slot>reject()</slot><hints><hint type="sourcelabel"><x>316</x><y>260</y></hint><hint type="destinationlabel"><x>286</x><y>274</y></hint></hints></connection></connections></ui>',
		dialog = Application.loadUi(ui),
		tableWidget = dialog.widgets.tableWidget;

	//tableWidget.setCurrentCell(2, 2);
	var itm = tableWidget.item(1, 2);
	print(JSON.stringify(itm));
	itm.checkState = undefined;
	itm.text = "New 1 2 Text";
	tableWidget.setItem(1, 2, itm);
	tableWidget.currentItem = itm;
	tableWidget.itemSelectionChanged.connect(tableWidget, function () {
		print("Selection changed");
		print(this.currentRow, this.currentColumn);
		print(this.selectedItems().length);
		var selItems = this.selectedItems();
		for (var i = 0; i < selItems.length; ++i) {
			print(selItems[i].text);
		}
	});

	dialog.exec();
}

/******************************************************************************************************
testArrayedData.qs
Copyright (C) 2011 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function testArrayedData() {
	var spec = nmr.activeSpectrum();
	if (!spec.isValid())
		return

	var arrData = spec.arrayedData;
	for (var i = 0; i < arrData.length; i++)
		arrData[i] = i;
	for (var prop in arrData)
		print(prop + " = " + arrData[prop]) // print all arrData's properties
	arrData.k = 10
	arrData.gtFormula = "t*k + 0.1"
	spec.arrayedData = arrData;

	var arrTable = mainWindow.getObject("NMRArrayedTable")
	if (arrTable)
		arrTable.updateData()
}

/******************************************************************************************************
testMolecularAssignmentsParser.qs
Copyright (C) 2019 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals Molecule, Atom, Str, mainWindow, print, MolecularAssignmentsParser*/
/*jslint plusplus: true, indent: 4*/


function testMolecularAssignmentsParser() {
	"use strict";

	var molecule, assignmentParser, i, j, k, assign, notAtom, atom,
		elements = ["C", "H", "N", "F"],
		shiftTypes = ["Peak", "Multiplet", "Integral"],
		labels = [],
		uuids = [],
		atoms = [],
		shifts = [],
		doc = mainWindow.activeDocument;

	function printFormatted(aObject) {
		print(JSON.stringify(aObject, null, 4) + "\n\n");
	}

	molecule = new Molecule(doc.item(0, "Molecule"));
	if (molecule && molecule.isValid()) {
		assignmentParser = new MolecularAssignmentsParser(molecule);
	} else {
		return;
	}

	for (i = 1; i < 4; i++) { //to collect uuids from first 3 atoms
		assign = assignmentParser.getFromAtomIndex(i);
		for (j = 0; j < assign.length; j++) {
			if (assign[j].shift[0].idTypes && assign[j].shift[0].idTypes.length) {
				for (k = 0; k < assign[j].shift[0].idTypes.length; k++) {
					uuids.push(assign[j].shift[0].idTypes[k].uuid);
				}
			}
		}
	}
	for (i = 0; i < 3; i++) { //to collect first 3 real labels, directly from assignments array
		labels.push(assignmentParser.assignments[i].atom.label);
	}
	for (i = 0; i < 3; i++) { //to collect first 3 atoms, directly from assignments array
		atom = {};
		atom.index = assignmentParser.assignments[i].atom.index;
		if (assignmentParser.assignments[i].atom.h) {
			atom.h = assignmentParser.assignments[i].atom.h;
		}
		atoms.push(atom);
	}
	for (i = 0; i < 3; i++) { //to collect first 3 shifts, directly from assignments array
		shifts.push(assignmentParser.assignments[i].shift[0].shift);
	}

	print("All asignments:\n");
	printFormatted(assignmentParser.getAll());

	//test index
	for (i = 1; i < 4; i++) {
		print("From atom index " + i + ":\n");
		printFormatted(assignmentParser.getFromAtomIndex(i));
	}
	print("From non existing atom index 10000:\n");
	printFormatted(assignmentParser.getFromAtomIndex(10000));


	//test element
	for (i = 0; i < elements.length; i++) {
		print("From element " + elements[i] + ":\n");
		printFormatted(assignmentParser.getFromAtomElement(elements[i]));
	}
	print("From non existing element UNKNOWN:\n");
	printFormatted(assignmentParser.getFromAtomElement("UNKNOWN"));


	//test type
	for (i = 0; i < shiftTypes.length; i++) {
		print("From shift type " + shiftTypes[i] + ":\n");
		printFormatted(assignmentParser.getFromShiftType(shiftTypes[i]));
	}
	print("From non existing shift type UNKNOWN:\n");
	printFormatted(assignmentParser.getFromShiftType("UNKNOWN"));


	//test label
	for (i = 0; i < labels.length; i++) {
		print("From label " + labels[i] + ":\n");
		printFormatted(assignmentParser.getFromAtomLabel(labels[i]));
	}
	print("From non existing label UNKNOWN:\n");
	printFormatted(assignmentParser.getFromAtomLabel("UNKNOWN"));


	//test uuid
	for (i = 0; i < uuids.length; i++) {
		print("From peak/multiplet/integral uuid " + uuids[i] + ":\n");
		printFormatted(assignmentParser.getFromShiftUUID(uuids[i]));
	}
	print("From non existing peak/multiplet/integral uuid UNKNOWN:\n");
	printFormatted(assignmentParser.getFromShiftUUID("UNKNOWN"));


	//test Atom
	for (i = 0; i < atoms.length; i++) {
		print("From atom " + JSON.stringify(atoms[i]) + ":\n");
		printFormatted(assignmentParser.getFromAtom(atoms[i]));
	}
	notAtom = { "index": 10000 };
	print("From non existing atom :" + JSON.stringify(notAtom) + ":\n");
	printFormatted(assignmentParser.getFromAtom(notAtom));


	//test Shift
	print("Note that getting atoms from shifts is less accurate, due to spectral overlap and shift variation due to experimental conditions\n\n");

	for (i = 0; i < atoms.length; i++) {
		print("From shift " + shifts[i] + " (will get all atoms with shifts within a range of 0.05ppm):\n");
		assignFromShift = assignmentParser.getFromShift(shifts[i]);
		printFormatted(assignFromShift);
		print("From shift " + shifts[i] + " using the previous output as input, to refine search (starting from a subset will get all atoms with shifts within a range of 0.01ppm):\n");
		printFormatted(assignmentParser.getFromShift(shifts[i], assignFromShift));
	}

	notShift = 10000;
	print("From non existing shift " + notShift + ":\n");
	printFormatted(assignmentParser.getFromShift(notShift));
}

/* textDocumentExample.qs */
function textDocumentExample() {
	var format = "odf",
		ui = Application.loadUi('<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"><class>Dialog</class><widget class="QDialog" name="Dialog"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>300</height></rect></property><property name="windowTitle"><string>Dialog</string></property><layout class="QGridLayout" name="gridLayout"><item row="1" column="0"><spacer name="horizontalSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>209</width><height>20</height></size></property></spacer></item><item row="1" column="1"><widget class="QPushButton" name="pushButton"><property name="text"><string>Save...</string></property></widget></item><item row="0" column="0" colspan="3"><widget class="QTextEdit" name="textEdit"/></item><item row="1" column="2"><widget class="QPushButton" name="printPushButton"><property name="text"><string>Print...</string></property></widget></item><item row="2" column="0" colspan="3"><widget class="QDialogButtonBox" name="buttonBox"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="standardButtons"><set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set></property></widget></item></layout></widget><resources><include location="untitled.qrc"/></resources><connections><connection><sender>buttonBox</sender><signal>accepted()</signal><receiver>Dialog</receiver><slot>accept()</slot><hints><hint type="sourcelabel"><x>248</x><y>254</y></hint><hint type="destinationlabel"><x>157</x><y>274</y></hint></hints></connection><connection><sender>buttonBox</sender><signal>rejected()</signal><receiver>Dialog</receiver><slot>reject()</slot><hints><hint type="sourcelabel"><x>316</x><y>260</y></hint><hint type="destinationlabel"><x>286</x><y>274</y></hint></hints></connection></connections></ui>'),
		html = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"><html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:"Bitstream Vera Sans"; font-size:11pt; font-weight:400; font-style:normal;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Mestrelab Research</span></p><p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p><p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Mestrelab Research</p><p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="image.png" /></p></body></html>',
		txtDoc = new TextDocument(ui.widgets.textEdit);

	txtDoc.addResourcePixmap("image.png", ":/background/MnovaMdiBack.png");
	txtDoc.setHtml(html);

	ui.widgets.pushButton.clicked.connect(function () {
		var out = FileDialog.getSaveFileName("ODF Documents (*.odf)", "Save document");
		if (out) {
			txtDoc.write(out, format);
		}
	})

	ui.widgets.printPushButton.clicked.connect(function () {
		var out = FileDialog.getSaveFileName("PDF Documents (*.pdf)", "Save document");
		if (out) {
			var printer = new Printer(Printer.ScreenResolution),
				docs = mainWindow.documents(),
				i = 0;
			printer.orientation = Printer.Portrait;
			printer.paperSize = Printer.A4;
			printer.begin(out);
			printer.print(txtDoc);
			printer.orientation = Printer.Landscape;
			for (i = 0; i < docs.length; ++i) {
				if (docs[i].pageItems.length) {
					printer.newPage();
					printer.print(docs[i]);
				}
			}
			printer.end();
		}
	})


	ui.exec();
}

/*******************************************************************************************
textStreamTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/
function textStreamTest() {
	var f = new File(Dir.temp() + "/MNova_TextStream_Test.txt");
	f.open(File.WriteOnly);
	print(f);

	var s = new TextStream(f);
	print(s);

	s1 = s;
	print(s1);

	var s2 = new TextStream(s);
	print(s2);

	var pi = 3.14159265358979;

	s.write("Hello World! ", 100, ",  \t", pi, "\n");
	s.write("Second line\n");
	s.writeln("Third line");
	s.precision = 10;
	s.write(pi, '\n');
	s.notation = TextStream.nScientific;
	s.write(pi, "\n");
	s.notation = TextStream.nFixed;
	s.write(pi, "\n");
	s.notation = TextStream.nSmart;
	s.write(pi, "\n");
	s.write("Last line");
	print(s);
	print(f);
	s.flush();
	print(f);

	f.close(); // important to call close() before opening in another mode
	print(f);
	f.open(File.ReadOnly);
	print(s);
	print(s.readLine());
	print(s.readLine());
	print(s.readLine());
	print(s.readLine());

	s.pos = 6;
	print(s);
	print(s.readLine());
	print(s.readLine());
	print(s.readLine());

	s.pos = 0;
	print(s.read(6));
	print(s.readAll());

	s.pos = 0;
	print(s.readString());
	print(s.readString());
	print(s.readNumber());
	print(s.readString());
	print(s.readLine());
	print(s.readLine());
	print(s.readLine());
	print(s.readNumber());

	f.close();
	f.remove();
	print(f);
}

/******************************************************************************************************
textTest.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function textTest() {
	var textItem = new Text(draw.text("Hello world!", false));
	print(textItem.plainText);
	print(textItem.htmlText);
	textItem.htmlText = "<b>Hello world!</b>";
	print(textItem.plainText);
	print(textItem.htmlText);
	textItem.update();
	mainWindow.activeWindow().update();
}

/******************************************************************************************************
toPositive.qs
Copyright (C) 2008 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function toPositive() {
	var spec = new NMRSpectrum(nmr.activeSpectrum());
	if (!spec.isValid && spec.dimCount == 1)
		return;

	nmr.beginModification(spec);
	for (var i = 0, size = spec.count(); i < size; i++)
		spec.setReal(i, Math.abs(spec.real(i)));
	nmr.endModification(spec);
}

/******************************************************************************************************
treeViewTest.qs
Copyright (C) 2019 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/*globals Application, StandardItemModel */
/*jslint plusplus: true, continue: true, bitwise: true*/

function treeViewTest() {

	"use strict";

	/* load the UI (it should contain a widget of type TreeView called treeView) */
	var treeViewDialog = Application.loadUiFile("ricares:treeViewTest.ui");

	/* create a new StandardItemModel object */
	var mySim = new StandardItemModel();

	/* define the main (0 and 1) branches and their children */
	var myObject000 = { text: "I am 000", flags: 33, children: [] };
	var myObject00 = { text: "I am 00", flags: 33, children: [myObject000] };
	var myObject01 = { text: "I am 01", flags: 33, children: [] };
	var myObject0 = { text: "I am 0", flags: 33, children: [myObject00, myObject01] };
	var myObject1 = { text: "I am 1", flags: 33, children: [] };

	/* populate the StandardItemModel */
	mySim.items = [myObject0, myObject1];

	/* get the info from the StandardItemModel */
	var myItems = mySim.items;

	/* overwrite the information of branch 0 (it will not overwrite its children) */
	myItems[0].text = "I am 0 (overwritten)";

	/* populate the StandardItemModel again with the updated info */
	mySim.items = myItems;

	/* define the header of the StandardItemModel */
	mySim.header = "This is my tree";

	/* load the model into the TreeView */
	treeViewDialog.widgets.treeView.setModel(mySim);
}

/******************************************************************************************************
updatePredictionDBTest.qs
Copyright (C) 2011 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/*jslint  */
/*global mainWindow, Application, print*/

function updatePredictionDBTest() {
	'use strict';
	var molItem = mainWindow.activeDocument.item(0, "Molecule");
	if (molItem.isValid()) {
		Application.NMRPredictor.silentMode = true;
		print("Exit Status: " + Application.NMRPredictor.updateUserDB("13C", molItem, "P")); //nucleus, item, dbletter
		Application.NMRPredictor.silentMode = false;
	} else {
		throw "Invalid Molecule";
	}
}

/******************************************************************************************************
verificationHandler.qs
Copyright (C) 2012 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
function verificationHandler(aPar) {
	var arg = JSON.parse(aPar)
	print(arg.molId)
	print(arg.itemIds)
	print(arg.resultId)

	var results = ASV.getResults(arg.itemIds[0], arg.molId)
	print("ASV Results Length: " + results.length)
	print(results)
	return true
}

Application.mainWindow.installEventHandler("verificationResult", "verificationHandler")


/******************************************************************************************************
waitForInputTest.qs
Copyright (C) 2009 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
function waitForInputTest() {
	var dialogTitle = "My Script Input Dialog";
	var firstStep = "Open a Spectrum";
	var secondStep = "Make a Zoom";
	var dialogMessage = "<ol><li>%1</li><li>%2</li></ol>";
	var val = Application.mainWindow.waitForInput(dialogMessage.replace("%1", boldString(firstStep)).replace("%2", secondStep), dialogTitle);
	if (val == 0)
		return val;
	val = Application.mainWindow.waitForInput(dialogMessage.replace("%1", firstStep).replace("%2", boldString(secondStep)), dialogTitle);
	if (val == 0)
		return val;

	var spc = new NMRSpectrum(nmr.activeSpectrum());
	if (spc.isValid()) {
		var sLimits = spc.getScaleLimits();
		var resultTemplate = new String("%1 Axis: From %2, To %3");
		var resultString = resultTemplate.replace("%1", "Horizontal").replace("%2", sLimits.fromX.toFixed(3)).replace("%3", sLimits.toX.toFixed(3));
		resultString += "\n" + resultTemplate.replace("%1", "Vertical").replace("%2", sLimits.fromY.toFixed(3)).replace("%3", sLimits.toY.toFixed(3));

		MessageBox.information("Selected Area:\n" + resultString, MessageBox.Ok);
	}
}

function boldString(aString) {
	return "<b>" + aString + "</b>";
}

/******************************************************************************************************
zipExample.qs
Copyright (C) 2016 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

function zipExample() {
	var file = FileDialog.getOpenFileName("*.*", "Zip File"),
		fileInfo = new FileInfo(file),
		d = fileInfo.dir,
		path = d.filePath("%1.zip".arg(fileInfo.suffix === "zip" ? fileInfo.fileName : fileInfo.baseName)),
		zip = new Zip(path);

	if (zip.open() === 0) {
		print(file, path);
		zip.addFile(file, "", Zip.SkipPaths);
	}
	zip.close();
}

function unzipExample() {
	var file = FileDialog.getOpenFileName("*.zip", "Unzip File"),
		fileInfo = new FileInfo(file),
		d = fileInfo.dir,
		outputDir = "%1_unzipped".arg(fileInfo.baseName),
		outPath = "",
		unzip;

	d.mkdir(outputDir),
		outPath = d.filePath(outputDir);

	print(outPath)
	unzip = new UnZip(file)
	if (unzip.open() === 0) {
		print(unzip.contents())
		unzip.extract(outPath)
		unzip.close()
	}
}
